Update wfdconfigmessage for supporting Wi-Fi Display sink side
[platform/core/multimedia/gst-rtsp-server-wfd.git] / src / rtsp-funnel.c
1 /* GStreamer
2  * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
3
4 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
5  *
6  * This library is free software; you can redistribute it and/or
7  * modify it under the terms of the GNU Library General Public
8  * License as published by the Free Software Foundation; either
9  * version 2 of the License, or (at your option) any later version.
10  *
11  * This library is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14  * Library General Public License for more details.
15  *
16  * You should have received a copy of the GNU Library General Public
17  * License along with this library; if not, write to the
18  * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
19  * Boston, MA 02111-1307, USA.
20  *
21
22 * * Modifications by Samsung Electronics Co., Ltd.
23
24 * 1. Applied Miracast WFD Server function
25 */
26
27 /**
28  * SECTION:element-rtspfunnel
29  * @short_description: N-to-1 simple funnel
30  *
31  * Takes packets from various input sinks into one output source
32  */
33
34 #ifdef HAVE_CONFIG_H
35 #  include "config.h"
36 #endif
37
38 #include "rtsp-funnel.h"
39
40 GST_DEBUG_CATEGORY_STATIC (rtsp_funnel_debug);
41 #define GST_CAT_DEFAULT rtsp_funnel_debug
42
43 static GstStaticPadTemplate funnel_sink_template =
44 GST_STATIC_PAD_TEMPLATE ("sink%d",
45     GST_PAD_SINK,
46     GST_PAD_REQUEST,
47     GST_STATIC_CAPS_ANY);
48
49 static GstStaticPadTemplate funnel_src_template =
50 GST_STATIC_PAD_TEMPLATE ("src",
51     GST_PAD_SRC,
52     GST_PAD_ALWAYS,
53     GST_STATIC_CAPS_ANY);
54
55
56 static void
57 _do_init (void)
58 {
59   GST_DEBUG_CATEGORY_INIT (rtsp_funnel_debug, "rtspfunnel", 0, "rtsp funnel element");
60 }
61
62 G_DEFINE_TYPE_EXTENDED(RTSPFunnel, rtsp_funnel, GST_TYPE_ELEMENT, 0, _do_init());
63
64
65 static GstStateChangeReturn rtsp_funnel_change_state (GstElement * element,
66     GstStateChange transition);
67
68 static GstPad *rtsp_funnel_request_new_pad (GstElement * element,
69     GstPadTemplate * templ, const gchar * name, const GstCaps *caps);
70 static void rtsp_funnel_release_pad (GstElement * element, GstPad * pad);
71
72 static GstFlowReturn rtsp_funnel_chain (GstPad * pad, GstObject *parent, GstBuffer * buffer);
73 static gboolean rtsp_funnel_event (GstPad * pad, GstObject *parent, GstEvent * event);
74 static gboolean rtsp_funnel_src_event (GstPad * pad, GstObject *parent, GstEvent * event);
75 static gboolean rtsp_funnel_query_caps (GstPad * pad, GstObject *parent, GstQuery *query);
76
77
78 typedef struct
79 {
80   GstSegment segment;
81 } RTSPFunnelPadPrivate;
82
83 static void
84 rtsp_funnel_base_init (gpointer g_class)
85 {
86 }
87
88
89 static void
90 rtsp_funnel_dispose (GObject * object)
91 {
92   GList *item;
93
94 restart:
95   for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
96     GstPad *pad = GST_PAD (item->data);
97
98     if (GST_PAD_IS_SINK (pad)) {
99       gst_element_release_request_pad (GST_ELEMENT (object), pad);
100       goto restart;
101     }
102   }
103
104   G_OBJECT_CLASS (rtsp_funnel_parent_class)->dispose (object);
105 }
106
107 static void
108 rtsp_funnel_class_init (RTSPFunnelClass * klass)
109 {
110   GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111   GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
112
113   gst_element_class_set_static_metadata(gstelement_class, "Farsight Funnel pipe fitting", "Generic", "N-to-1 pipe fitting", "Olivier Crete <olivier.crete@collabora.co.uk>");
114
115   gst_element_class_add_pad_template (gstelement_class,
116       gst_static_pad_template_get (&funnel_sink_template));
117   gst_element_class_add_pad_template (gstelement_class,
118       gst_static_pad_template_get (&funnel_src_template));
119
120   gobject_class->dispose = GST_DEBUG_FUNCPTR (rtsp_funnel_dispose);
121
122   gstelement_class->request_new_pad =
123       GST_DEBUG_FUNCPTR (rtsp_funnel_request_new_pad);
124   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (rtsp_funnel_release_pad);
125   gstelement_class->change_state = GST_DEBUG_FUNCPTR (rtsp_funnel_change_state);
126 }
127
128 static void
129 rtsp_funnel_init (RTSPFunnel * funnel)
130 {
131   funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template,
132       "src");
133   gst_pad_set_event_function (funnel->srcpad, rtsp_funnel_src_event);
134   gst_pad_use_fixed_caps (funnel->srcpad);
135   gst_element_add_pad (GST_ELEMENT (funnel), funnel->srcpad);
136 }
137
138 static GstPad *
139 rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
140     const gchar * name, const GstCaps *caps)
141 {
142   GstPad *sinkpad;
143   RTSPFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (RTSPFunnelPadPrivate));
144
145   GST_DEBUG_OBJECT (element, "requesting pad");
146
147   sinkpad = gst_pad_new_from_template (templ, name);
148
149   gst_pad_set_chain_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_chain));
150   gst_pad_set_event_function (sinkpad, GST_DEBUG_FUNCPTR (rtsp_funnel_event));
151
152   gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
153   gst_pad_set_element_private (sinkpad, priv);
154
155   gst_pad_set_active (sinkpad, TRUE);
156
157   gst_element_add_pad (element, sinkpad);
158
159   return sinkpad;
160 }
161
162 static void
163 rtsp_funnel_release_pad (GstElement * element, GstPad * pad)
164 {
165   RTSPFunnel *funnel = RTSP_FUNNEL (element);
166   RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
167
168   GST_DEBUG_OBJECT (funnel, "releasing pad");
169
170   gst_pad_set_active (pad, FALSE);
171
172   if (priv)
173     g_slice_free1 (sizeof (RTSPFunnelPadPrivate), priv);
174
175   gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad);
176 }
177
178 static GstFlowReturn
179 rtsp_funnel_chain (GstPad * pad, GstObject *parent, GstBuffer * buffer)
180 {
181   GstFlowReturn res;
182   RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
183   RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
184   GstEvent *event = NULL;
185   GstClockTime newts;
186   GstCaps *padcaps;
187
188   GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);
189
190   GST_OBJECT_LOCK (funnel);
191   if (priv->segment.format == GST_FORMAT_UNDEFINED) {
192     GST_WARNING_OBJECT (funnel, "Got buffer without segment,"
193         " setting segment [0,inf[");
194     priv->segment.rate = 1.0;
195     priv->segment.applied_rate = 1.0;
196     priv->segment.format = GST_FORMAT_TIME;
197     priv->segment.start = 0;
198     priv->segment.stop = -1;
199     priv->segment.time = 0;
200   }
201
202   if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
203       priv->segment.position = GST_BUFFER_TIMESTAMP (buffer);
204
205   newts = gst_segment_to_running_time (&priv->segment,
206       priv->segment.format, GST_BUFFER_TIMESTAMP (buffer));
207   if (newts != GST_BUFFER_TIMESTAMP (buffer)) {
208     buffer = gst_buffer_make_writable (buffer);
209     GST_BUFFER_TIMESTAMP (buffer) = newts;
210   }
211
212   if (!funnel->has_segment) {
213       GstSegment *segment = gst_segment_new();
214       gst_segment_init(segment, GST_FORMAT_TIME);
215       segment->rate = 1.0;
216       segment->applied_rate = 1.0;
217       segment->start = 0;
218       segment->stop = -1;
219       segment->time = 0;
220       gst_event_new_segment(segment);
221     funnel->has_segment = TRUE;
222   }
223   GST_OBJECT_UNLOCK (funnel);
224
225   if (event) {
226     if (!gst_pad_push_event (funnel->srcpad, event)) {
227       GST_WARNING_OBJECT (funnel, "Could not push out newsegment event");
228       res = GST_FLOW_ERROR;
229       goto out;
230     }
231   }
232
233
234   GST_OBJECT_LOCK (pad);
235   padcaps = gst_pad_get_current_caps(funnel->srcpad);
236   GST_OBJECT_UNLOCK (pad);
237
238   res = gst_pad_push (funnel->srcpad, buffer);
239
240   GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));
241
242 out:
243   gst_object_unref (funnel);
244
245   return res;
246 }
247
248 static gboolean
249 rtsp_funnel_event (GstPad * pad, GstObject *parent, GstEvent * event)
250 {
251   RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
252   RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
253   gboolean forward = TRUE;
254   gboolean res = TRUE;
255
256   switch (GST_EVENT_TYPE (event)) {
257     case GST_EVENT_SEGMENT:
258     {
259       GstSegment *segment = gst_segment_new();
260       gst_segment_init(segment, GST_FORMAT_UNDEFINED);
261       gst_event_parse_segment(event, &segment);
262       GST_OBJECT_LOCK (funnel);
263       gst_segment_copy_into(segment, &priv->segment);
264       GST_OBJECT_UNLOCK (funnel);
265       gst_segment_free(segment);
266
267       forward = FALSE;
268       gst_event_unref (event);
269     }
270       break;
271     case GST_EVENT_FLUSH_STOP:
272     {
273       GST_OBJECT_LOCK (funnel);
274       gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
275       GST_OBJECT_UNLOCK (funnel);
276     }
277       break;
278     default:
279       break;
280   }
281
282
283   if (forward)
284     res = gst_pad_push_event (funnel->srcpad, event);
285
286   gst_object_unref (funnel);
287
288   return res;
289 }
290
291 static gboolean
292 rtsp_funnel_src_event (GstPad * pad, GstObject *parent, GstEvent * event)
293 {
294   GstElement *funnel;
295   GstIterator *iter;
296   GstPad *sinkpad;
297   gboolean result = FALSE;
298   gboolean done = FALSE;
299
300   funnel = gst_pad_get_parent_element (pad);
301   g_return_val_if_fail (funnel != NULL, FALSE);
302
303   iter = gst_element_iterate_sink_pads (funnel);
304
305   while (!done) {
306     switch (gst_iterator_next (iter, (gpointer) & sinkpad)) {
307       case GST_ITERATOR_OK:
308         gst_event_ref (event);
309         result |= gst_pad_push_event (sinkpad, event);
310         gst_object_unref (sinkpad);
311         break;
312       case GST_ITERATOR_RESYNC:
313         gst_iterator_resync (iter);
314         result = FALSE;
315         break;
316       case GST_ITERATOR_ERROR:
317         GST_WARNING_OBJECT (funnel, "Error iterating sinkpads");
318       case GST_ITERATOR_DONE:
319         done = TRUE;
320         break;
321     }
322   }
323   gst_iterator_free (iter);
324   gst_object_unref (funnel);
325   gst_event_unref (event);
326
327   return result;
328 }
329
330 static void
331 reset_pad (const GValue * item, gpointer user_data)
332 {
333   GstPad *pad = GST_PAD(item);
334   RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
335
336   GST_OBJECT_LOCK (pad);
337   gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
338   GST_OBJECT_UNLOCK (pad);
339   gst_object_unref (pad);
340 }
341
342 static GstStateChangeReturn
343 rtsp_funnel_change_state (GstElement * element, GstStateChange transition)
344 {
345   RTSPFunnel *funnel = RTSP_FUNNEL (element);
346   GstStateChangeReturn ret;
347
348   switch (transition) {
349     case GST_STATE_CHANGE_READY_TO_PAUSED:
350     {
351       GstIterator *iter = gst_element_iterate_sink_pads (element);
352       GstIteratorResult res;
353
354       do {
355         res = gst_iterator_foreach (iter, reset_pad, NULL);
356       } while (res == GST_ITERATOR_RESYNC);
357
358       gst_iterator_free (iter);
359
360       if (res == GST_ITERATOR_ERROR)
361         return GST_STATE_CHANGE_FAILURE;
362
363       GST_OBJECT_LOCK (funnel);
364       funnel->has_segment = FALSE;
365       GST_OBJECT_UNLOCK (funnel);
366     }
367       break;
368     default:
369       break;
370   }
371
372   ret = GST_ELEMENT_CLASS (rtsp_funnel_parent_class)->change_state (element, transition);
373
374   return ret;
375 }