2 * Copyright (C) 2008 Wim Taymans <wim.taymans at gmail.com>
4 * Copyright (c) 2012, 2013 Samsung Electronics Co., Ltd.
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.
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.
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.
22 * * Modifications by Samsung Electronics Co., Ltd.
24 * 1. Applied Miracast WFD Server function
28 * SECTION:element-rtspfunnel
29 * @short_description: N-to-1 simple funnel
31 * Takes packets from various input sinks into one output source
38 #include "rtsp-funnel.h"
40 GST_DEBUG_CATEGORY_STATIC (rtsp_funnel_debug);
41 #define GST_CAT_DEFAULT rtsp_funnel_debug
43 static GstStaticPadTemplate funnel_sink_template =
44 GST_STATIC_PAD_TEMPLATE ("sink%d",
49 static GstStaticPadTemplate funnel_src_template =
50 GST_STATIC_PAD_TEMPLATE ("src",
59 GST_DEBUG_CATEGORY_INIT (rtsp_funnel_debug, "rtspfunnel", 0, "rtsp funnel element");
62 G_DEFINE_TYPE_EXTENDED(RTSPFunnel, rtsp_funnel, GST_TYPE_ELEMENT, 0, _do_init());
65 static GstStateChangeReturn rtsp_funnel_change_state (GstElement * element,
66 GstStateChange transition);
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);
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);
81 } RTSPFunnelPadPrivate;
84 rtsp_funnel_base_init (gpointer g_class)
90 rtsp_funnel_dispose (GObject * object)
95 for (item = GST_ELEMENT_PADS (object); item; item = g_list_next (item)) {
96 GstPad *pad = GST_PAD (item->data);
98 if (GST_PAD_IS_SINK (pad)) {
99 gst_element_release_request_pad (GST_ELEMENT (object), pad);
104 G_OBJECT_CLASS (rtsp_funnel_parent_class)->dispose (object);
108 rtsp_funnel_class_init (RTSPFunnelClass * klass)
110 GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
111 GstElementClass *gstelement_class = GST_ELEMENT_CLASS (klass);
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>");
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));
120 gobject_class->dispose = GST_DEBUG_FUNCPTR (rtsp_funnel_dispose);
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);
129 rtsp_funnel_init (RTSPFunnel * funnel)
131 funnel->srcpad = gst_pad_new_from_static_template (&funnel_src_template,
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);
139 rtsp_funnel_request_new_pad (GstElement * element, GstPadTemplate * templ,
140 const gchar * name, const GstCaps *caps)
143 RTSPFunnelPadPrivate *priv = g_slice_alloc0 (sizeof (RTSPFunnelPadPrivate));
145 GST_DEBUG_OBJECT (element, "requesting pad");
147 sinkpad = gst_pad_new_from_template (templ, name);
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));
152 gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
153 gst_pad_set_element_private (sinkpad, priv);
155 gst_pad_set_active (sinkpad, TRUE);
157 gst_element_add_pad (element, sinkpad);
163 rtsp_funnel_release_pad (GstElement * element, GstPad * pad)
165 RTSPFunnel *funnel = RTSP_FUNNEL (element);
166 RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
168 GST_DEBUG_OBJECT (funnel, "releasing pad");
170 gst_pad_set_active (pad, FALSE);
173 g_slice_free1 (sizeof (RTSPFunnelPadPrivate), priv);
175 gst_element_remove_pad (GST_ELEMENT_CAST (funnel), pad);
179 rtsp_funnel_chain (GstPad * pad, GstObject *parent, GstBuffer * buffer)
182 RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
183 RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
184 GstEvent *event = NULL;
188 GST_DEBUG_OBJECT (funnel, "received buffer %p", buffer);
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;
202 if (GST_CLOCK_TIME_IS_VALID (GST_BUFFER_TIMESTAMP (buffer)))
203 priv->segment.position = GST_BUFFER_TIMESTAMP (buffer);
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;
212 if (!funnel->has_segment) {
213 GstSegment *segment = gst_segment_new();
214 gst_segment_init(segment, GST_FORMAT_TIME);
216 segment->applied_rate = 1.0;
220 gst_event_new_segment(segment);
221 funnel->has_segment = TRUE;
223 GST_OBJECT_UNLOCK (funnel);
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;
234 GST_OBJECT_LOCK (pad);
235 padcaps = gst_pad_get_current_caps(funnel->srcpad);
236 GST_OBJECT_UNLOCK (pad);
238 res = gst_pad_push (funnel->srcpad, buffer);
240 GST_LOG_OBJECT (funnel, "handled buffer %s", gst_flow_get_name (res));
243 gst_object_unref (funnel);
249 rtsp_funnel_event (GstPad * pad, GstObject *parent, GstEvent * event)
251 RTSPFunnel *funnel = RTSP_FUNNEL (gst_pad_get_parent (pad));
252 RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
253 gboolean forward = TRUE;
256 switch (GST_EVENT_TYPE (event)) {
257 case GST_EVENT_SEGMENT:
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);
268 gst_event_unref (event);
271 case GST_EVENT_FLUSH_STOP:
273 GST_OBJECT_LOCK (funnel);
274 gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
275 GST_OBJECT_UNLOCK (funnel);
284 res = gst_pad_push_event (funnel->srcpad, event);
286 gst_object_unref (funnel);
292 rtsp_funnel_src_event (GstPad * pad, GstObject *parent, GstEvent * event)
297 gboolean result = FALSE;
298 gboolean done = FALSE;
300 funnel = gst_pad_get_parent_element (pad);
301 g_return_val_if_fail (funnel != NULL, FALSE);
303 iter = gst_element_iterate_sink_pads (funnel);
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);
312 case GST_ITERATOR_RESYNC:
313 gst_iterator_resync (iter);
316 case GST_ITERATOR_ERROR:
317 GST_WARNING_OBJECT (funnel, "Error iterating sinkpads");
318 case GST_ITERATOR_DONE:
323 gst_iterator_free (iter);
324 gst_object_unref (funnel);
325 gst_event_unref (event);
331 reset_pad (const GValue * item, gpointer user_data)
333 GstPad *pad = GST_PAD(item);
334 RTSPFunnelPadPrivate *priv = gst_pad_get_element_private (pad);
336 GST_OBJECT_LOCK (pad);
337 gst_segment_init (&priv->segment, GST_FORMAT_UNDEFINED);
338 GST_OBJECT_UNLOCK (pad);
339 gst_object_unref (pad);
342 static GstStateChangeReturn
343 rtsp_funnel_change_state (GstElement * element, GstStateChange transition)
345 RTSPFunnel *funnel = RTSP_FUNNEL (element);
346 GstStateChangeReturn ret;
348 switch (transition) {
349 case GST_STATE_CHANGE_READY_TO_PAUSED:
351 GstIterator *iter = gst_element_iterate_sink_pads (element);
352 GstIteratorResult res;
355 res = gst_iterator_foreach (iter, reset_pad, NULL);
356 } while (res == GST_ITERATOR_RESYNC);
358 gst_iterator_free (iter);
360 if (res == GST_ITERATOR_ERROR)
361 return GST_STATE_CHANGE_FAILURE;
363 GST_OBJECT_LOCK (funnel);
364 funnel->has_segment = FALSE;
365 GST_OBJECT_UNLOCK (funnel);
372 ret = GST_ELEMENT_CLASS (rtsp_funnel_parent_class)->change_state (element, transition);