2 * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.com>
4 * This library is free software; you can redistribute it and/or
5 * modify it under the terms of the GNU Library General Public
6 * License as published by the Free Software Foundation; either
7 * version 2 of the License, or (at your option) any later version.
9 * This library is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 * Library General Public License for more details.
14 * You should have received a copy of the GNU Library General Public
15 * License along with this library; if not, write to the
16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
17 * Boston, MA 02111-1307, USA.
20 * Unless otherwise indicated, Source Code is licensed under MIT license.
21 * See further explanation attached in License Statement (distributed in the file
24 * Permission is hereby granted, free of charge, to any person obtaining a copy of
25 * this software and associated documentation files (the "Software"), to deal in
26 * the Software without restriction, including without limitation the rights to
27 * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
28 * of the Software, and to permit persons to whom the Software is furnished to do
29 * so, subject to the following conditions:
31 * The above copyright notice and this permission notice shall be included in all
32 * copies or substantial portions of the Software.
34 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
35 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
36 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
37 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
38 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
39 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
42 /* Element-Checklist-Version: 5 */
45 * SECTION:element-rtpdec
47 * A simple RTP session manager used internally by rtspsrc.
49 * Last reviewed on 2006-06-20 (0.10.4)
52 /* #define HAVE_RTCP */
54 #include <gst/rtp/gstrtpbuffer.h>
57 #include <gst/rtp/gstrtcpbuffer.h>
60 #include "gstrtpdec.h"
63 GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
64 #define GST_CAT_DEFAULT (rtpdec_debug)
66 /* GstRTPDec signals and args */
69 SIGNAL_REQUEST_PT_MAP,
73 SIGNAL_ON_SSRC_COLLISION,
74 SIGNAL_ON_SSRC_VALIDATED,
76 SIGNAL_ON_BYE_TIMEOUT,
81 #define DEFAULT_LATENCY_MS 200
89 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
93 GST_STATIC_CAPS ("application/x-rtp")
96 static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
97 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
100 GST_STATIC_CAPS ("application/x-rtcp")
103 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
104 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
107 GST_STATIC_CAPS ("application/x-rtp")
110 static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
111 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
114 GST_STATIC_CAPS ("application/x-rtcp")
117 static void gst_rtp_dec_finalize (GObject * object);
118 static void gst_rtp_dec_set_property (GObject * object,
119 guint prop_id, const GValue * value, GParamSpec * pspec);
120 static void gst_rtp_dec_get_property (GObject * object,
121 guint prop_id, GValue * value, GParamSpec * pspec);
123 static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
124 static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
125 GstStateChange transition);
126 static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
127 GstPadTemplate * templ, const gchar * name, const GstCaps * caps);
128 static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
130 static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent,
132 static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent,
136 /* Manages the receiving end of the packets.
138 * There is one such structure for each RTP session (audio/video/...).
139 * We get the RTP/RTCP packets and stuff them into the session manager.
141 struct _GstRTPDecSession
149 /* we only support one ssrc and one pt */
154 /* the pads of the session */
155 GstPad *recv_rtp_sink;
156 GstPad *recv_rtp_src;
157 GstPad *recv_rtcp_sink;
161 /* find a session with the given id */
162 static GstRTPDecSession *
163 find_session_by_id (GstRTPDec * rtpdec, gint id)
167 for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
168 GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
176 /* create a session with the given id */
177 static GstRTPDecSession *
178 create_session (GstRTPDec * rtpdec, gint id)
180 GstRTPDecSession *sess;
182 sess = g_new0 (GstRTPDecSession, 1);
185 rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
191 free_session (GstRTPDecSession * session)
196 static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
198 #define gst_rtp_dec_parent_class parent_class
199 G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
202 /* BOXED:UINT,UINT */
203 #define g_marshal_value_peek_uint(v) g_value_get_uint (v)
206 gst_rtp_dec_marshal_BOXED__UINT_UINT (GClosure * closure,
207 GValue * return_value,
208 guint n_param_values,
209 const GValue * param_values,
210 gpointer invocation_hint, gpointer marshal_data)
212 typedef gpointer (*GMarshalFunc_BOXED__UINT_UINT) (gpointer data1,
213 guint arg_1, guint arg_2, gpointer data2);
214 register GMarshalFunc_BOXED__UINT_UINT callback;
215 register GCClosure *cc = (GCClosure *) closure;
216 register gpointer data1, data2;
219 g_return_if_fail (return_value != NULL);
220 g_return_if_fail (n_param_values == 3);
222 if (G_CCLOSURE_SWAP_DATA (closure)) {
223 data1 = closure->data;
224 data2 = g_value_peek_pointer (param_values + 0);
226 data1 = g_value_peek_pointer (param_values + 0);
227 data2 = closure->data;
230 (GMarshalFunc_BOXED__UINT_UINT) (marshal_data ? marshal_data :
233 v_return = callback (data1,
234 g_marshal_value_peek_uint (param_values + 1),
235 g_marshal_value_peek_uint (param_values + 2), data2);
237 g_value_take_boxed (return_value, v_return);
241 gst_rtp_dec_marshal_VOID__UINT_UINT (GClosure * closure,
242 GValue * return_value,
243 guint n_param_values,
244 const GValue * param_values,
245 gpointer invocation_hint, gpointer marshal_data)
247 typedef void (*GMarshalFunc_VOID__UINT_UINT) (gpointer data1,
248 guint arg_1, guint arg_2, gpointer data2);
249 register GMarshalFunc_VOID__UINT_UINT callback;
250 register GCClosure *cc = (GCClosure *) closure;
251 register gpointer data1, data2;
253 g_return_if_fail (n_param_values == 3);
255 if (G_CCLOSURE_SWAP_DATA (closure)) {
256 data1 = closure->data;
257 data2 = g_value_peek_pointer (param_values + 0);
259 data1 = g_value_peek_pointer (param_values + 0);
260 data2 = closure->data;
263 (GMarshalFunc_VOID__UINT_UINT) (marshal_data ? marshal_data :
267 g_marshal_value_peek_uint (param_values + 1),
268 g_marshal_value_peek_uint (param_values + 2), data2);
272 gst_rtp_dec_class_init (GstRTPDecClass * g_class)
274 GObjectClass *gobject_class;
275 GstElementClass *gstelement_class;
276 GstRTPDecClass *klass;
278 klass = (GstRTPDecClass *) g_class;
279 gobject_class = (GObjectClass *) klass;
280 gstelement_class = (GstElementClass *) klass;
282 GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
284 gobject_class->finalize = gst_rtp_dec_finalize;
285 gobject_class->set_property = gst_rtp_dec_set_property;
286 gobject_class->get_property = gst_rtp_dec_get_property;
288 g_object_class_install_property (gobject_class, PROP_LATENCY,
289 g_param_spec_uint ("latency", "Buffer latency in ms",
290 "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
291 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
294 * GstRTPDec::request-pt-map:
295 * @rtpdec: the object which received the signal
296 * @session: the session
299 * Request the payload type as #GstCaps for @pt in @session.
301 gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
302 g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
303 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map),
304 NULL, NULL, gst_rtp_dec_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
305 G_TYPE_UINT, G_TYPE_UINT);
307 gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
308 g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
309 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map),
310 NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
313 * GstRTPDec::on-new-ssrc:
314 * @rtpbin: the object which received the signal
315 * @session: the session
318 * Notify of a new SSRC that entered @session.
320 gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
321 g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
322 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc),
323 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
324 G_TYPE_UINT, G_TYPE_UINT);
326 * GstRTPDec::on-ssrc_collision:
327 * @rtpbin: the object which received the signal
328 * @session: the session
331 * Notify when we have an SSRC collision
333 gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
334 g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
335 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
336 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
337 G_TYPE_UINT, G_TYPE_UINT);
339 * GstRTPDec::on-ssrc_validated:
340 * @rtpbin: the object which received the signal
341 * @session: the session
344 * Notify of a new SSRC that became validated.
346 gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
347 g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
348 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
349 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
350 G_TYPE_UINT, G_TYPE_UINT);
353 * GstRTPDec::on-bye-ssrc:
354 * @rtpbin: the object which received the signal
355 * @session: the session
358 * Notify of an SSRC that became inactive because of a BYE packet.
360 gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
361 g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
362 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc),
363 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
364 G_TYPE_UINT, G_TYPE_UINT);
366 * GstRTPDec::on-bye-timeout:
367 * @rtpbin: the object which received the signal
368 * @session: the session
371 * Notify of an SSRC that has timed out because of BYE
373 gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
374 g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
375 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
376 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
377 G_TYPE_UINT, G_TYPE_UINT);
379 * GstRTPDec::on-timeout:
380 * @rtpbin: the object which received the signal
381 * @session: the session
384 * Notify of an SSRC that has timed out
386 gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
387 g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
388 G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout),
389 NULL, NULL, gst_rtp_dec_marshal_VOID__UINT_UINT, G_TYPE_NONE, 2,
390 G_TYPE_UINT, G_TYPE_UINT);
392 gstelement_class->provide_clock =
393 GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
394 gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
395 gstelement_class->request_new_pad =
396 GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
397 gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
400 gst_element_class_add_pad_template (gstelement_class,
401 gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_sink_template));
402 gst_element_class_add_pad_template (gstelement_class,
403 gst_static_pad_template_get (&gst_rtp_dec_recv_rtcp_sink_template));
405 gst_element_class_add_pad_template (gstelement_class,
406 gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_src_template));
407 gst_element_class_add_pad_template (gstelement_class,
408 gst_static_pad_template_get (&gst_rtp_dec_rtcp_src_template));
410 gst_element_class_set_details_simple (gstelement_class, "RTP Decoder",
411 "Codec/Parser/Network",
412 "Accepts raw RTP and RTCP packets and sends them forward",
413 "Wim Taymans <wim.taymans@gmail.com>");
417 gst_rtp_dec_init (GstRTPDec * rtpdec)
419 rtpdec->provided_clock = gst_system_clock_obtain ();
420 rtpdec->latency = DEFAULT_LATENCY_MS;
422 GST_OBJECT_FLAG_SET (rtpdec, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
426 gst_rtp_dec_finalize (GObject * object)
430 rtpdec = GST_RTP_DEC (object);
432 g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
433 g_slist_free (rtpdec->sessions);
435 G_OBJECT_CLASS (parent_class)->finalize (object);
439 gst_rtp_dec_query_src (GstPad * pad, GstObject * parent, GstQuery * query)
443 switch (GST_QUERY_TYPE (query)) {
444 case GST_QUERY_LATENCY:
446 /* we pretend to be live with a 3 second latency */
447 gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
452 res = gst_pad_query_default (pad, parent, query);
459 gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
463 GstRTPDecSession *session;
466 GstRTPBuffer rtp = { NULL, };
468 rtpdec = GST_RTP_DEC (parent);
470 GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
472 if (!gst_rtp_buffer_validate (buffer))
476 gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp);
477 ssrc = gst_rtp_buffer_get_ssrc (&rtp);
478 pt = gst_rtp_buffer_get_payload_type (&rtp);
479 gst_rtp_buffer_unmap (&rtp);
481 GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
484 session = gst_pad_get_element_private (pad);
486 /* see if we have the pad */
487 if (!session->active) {
488 GstPadTemplate *templ;
489 GstElementClass *klass;
493 GValue args[3] = { {0}
498 GST_DEBUG_OBJECT (rtpdec, "creating stream");
500 session->ssrc = ssrc;
504 g_value_init (&args[0], GST_TYPE_ELEMENT);
505 g_value_set_object (&args[0], rtpdec);
506 g_value_init (&args[1], G_TYPE_UINT);
507 g_value_set_uint (&args[1], session->id);
508 g_value_init (&args[2], G_TYPE_UINT);
509 g_value_set_uint (&args[2], pt);
511 g_value_init (&ret, GST_TYPE_CAPS);
512 g_value_set_boxed (&ret, NULL);
514 g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
516 caps = (GstCaps *) g_value_get_boxed (&ret);
518 name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
519 klass = GST_ELEMENT_GET_CLASS (rtpdec);
520 templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
521 session->recv_rtp_src = gst_pad_new_from_template (templ, name);
524 gst_pad_push_event (session->recv_rtp_src, gst_event_new_caps (caps));
526 gst_pad_set_element_private (session->recv_rtp_src, session);
527 gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
528 gst_pad_set_active (session->recv_rtp_src, TRUE);
529 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
531 session->active = TRUE;
534 res = gst_pad_push (session->recv_rtp_src, buffer);
540 GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
541 ("RTP packet did not validate, dropping"));
542 gst_buffer_unref (buffer);
548 gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
554 GstRTCPPacket packet;
558 src = GST_RTP_DEC (parent);
560 GST_DEBUG_OBJECT (src, "got rtcp packet");
563 valid = gst_rtcp_buffer_validate (buffer);
567 /* position on first packet */
568 more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
570 switch (gst_rtcp_packet_get_type (&packet)) {
571 case GST_RTCP_TYPE_SR:
573 guint32 ssrc, rtptime, packet_count, octet_count;
577 gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
578 &packet_count, &octet_count);
580 GST_DEBUG_OBJECT (src,
581 "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
582 ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
585 count = gst_rtcp_packet_get_rb_count (&packet);
586 for (i = 0; i < count; i++) {
587 guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
591 gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
592 &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
594 GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
595 ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
596 packetslost, exthighestseq, jitter, lsr, dlsr);
600 case GST_RTCP_TYPE_RR:
605 ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
607 GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
609 count = gst_rtcp_packet_get_rb_count (&packet);
610 for (i = 0; i < count; i++) {
611 guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
615 gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
616 &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
618 GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
619 ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
620 packetslost, exthighestseq, jitter, lsr, dlsr);
624 case GST_RTCP_TYPE_SDES:
627 gboolean more_chunks, more_items;
629 chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
630 GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
632 more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
634 while (more_chunks) {
637 ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
639 GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
641 more_items = gst_rtcp_packet_sdes_first_item (&packet);
644 GstRTCPSDESType type;
648 gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
650 GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
653 more_items = gst_rtcp_packet_sdes_next_item (&packet);
656 more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
661 case GST_RTCP_TYPE_BYE:
666 reason = gst_rtcp_packet_bye_get_reason (&packet);
667 GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
668 GST_STR_NULL (reason));
671 count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
672 for (i = 0; i < count; i++) {
676 ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
678 GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
682 case GST_RTCP_TYPE_APP:
683 GST_DEBUG_OBJECT (src, "got APP packet");
686 GST_WARNING_OBJECT (src, "got unknown RTCP packet");
689 more = gst_rtcp_packet_move_to_next (&packet);
691 gst_buffer_unref (buffer);
696 GST_WARNING_OBJECT (src, "got invalid RTCP packet");
697 gst_buffer_unref (buffer);
701 gst_buffer_unref (buffer);
707 gst_rtp_dec_set_property (GObject * object, guint prop_id,
708 const GValue * value, GParamSpec * pspec)
712 src = GST_RTP_DEC (object);
716 src->latency = g_value_get_uint (value);
719 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
725 gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
730 src = GST_RTP_DEC (object);
734 g_value_set_uint (value, src->latency);
737 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
743 gst_rtp_dec_provide_clock (GstElement * element)
747 rtpdec = GST_RTP_DEC (element);
749 return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
752 static GstStateChangeReturn
753 gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
755 GstStateChangeReturn ret;
757 switch (transition) {
762 ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
764 switch (transition) {
765 case GST_STATE_CHANGE_READY_TO_PAUSED:
766 case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
767 /* we're NO_PREROLL when going to PAUSED */
768 ret = GST_STATE_CHANGE_NO_PREROLL;
777 /* Create a pad for receiving RTP for the session in @name
780 create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
783 GstRTPDecSession *session;
785 /* first get the session number */
786 if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
789 GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
791 /* get or create session */
792 session = find_session_by_id (rtpdec, sessid);
794 GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
795 /* create session now */
796 session = create_session (rtpdec, sessid);
800 /* check if pad was requested */
801 if (session->recv_rtp_sink != NULL)
804 GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
806 session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
807 gst_pad_set_element_private (session->recv_rtp_sink, session);
808 gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
809 gst_pad_set_active (session->recv_rtp_sink, TRUE);
810 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
812 return session->recv_rtp_sink;
817 g_warning ("rtpdec: invalid name given");
822 /* create_session already warned */
827 g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
832 /* Create a pad for receiving RTCP for the session in @name
835 create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
839 GstRTPDecSession *session;
841 /* first get the session number */
842 if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
845 GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
847 /* get the session, it must exist or we error */
848 session = find_session_by_id (rtpdec, sessid);
852 /* check if pad was requested */
853 if (session->recv_rtcp_sink != NULL)
856 GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
858 session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
859 gst_pad_set_element_private (session->recv_rtp_sink, session);
860 gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
861 gst_pad_set_active (session->recv_rtcp_sink, TRUE);
862 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
864 return session->recv_rtcp_sink;
869 g_warning ("rtpdec: invalid name given");
874 g_warning ("rtpdec: no session with id %d", sessid);
879 g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
885 /* Create a pad for sending RTCP for the session in @name
888 create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
891 GstRTPDecSession *session;
893 /* first get the session number */
894 if (name == NULL || sscanf (name, "rtcp_src_%u", &sessid) != 1)
897 /* get or create session */
898 session = find_session_by_id (rtpdec, sessid);
902 /* check if pad was requested */
903 if (session->rtcp_src != NULL)
906 session->rtcp_src = gst_pad_new_from_template (templ, name);
907 gst_pad_set_active (session->rtcp_src, TRUE);
908 gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
910 return session->rtcp_src;
915 g_warning ("rtpdec: invalid name given");
920 g_warning ("rtpdec: session with id %d does not exist", sessid);
925 g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
933 gst_rtp_dec_request_new_pad (GstElement * element,
934 GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
937 GstElementClass *klass;
940 g_return_val_if_fail (templ != NULL, NULL);
941 g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
943 rtpdec = GST_RTP_DEC (element);
944 klass = GST_ELEMENT_GET_CLASS (element);
946 /* figure out the template */
947 if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
948 result = create_recv_rtp (rtpdec, templ, name);
949 } else if (templ == gst_element_class_get_pad_template (klass,
950 "recv_rtcp_sink_%u")) {
951 result = create_recv_rtcp (rtpdec, templ, name);
952 } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%u")) {
953 result = create_rtcp (rtpdec, templ, name);
962 g_warning ("rtpdec: this is not our template");
968 gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)