• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /* GStreamer
2  * Copyright (C) <2005,2006> Wim Taymans <wim.taymans@gmail.com>
3  *
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.
8  *
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.
13  *
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., 51 Franklin St, Fifth Floor,
17  * Boston, MA 02110-1301, USA.
18  */
19 /*
20  * Unless otherwise indicated, Source Code is licensed under MIT license.
21  * See further explanation attached in License Statement (distributed in the file
22  * LICENSE).
23  *
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:
30  *
31  * The above copyright notice and this permission notice shall be included in all
32  * copies or substantial portions of the Software.
33  *
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
40  * SOFTWARE.
41  */
42 /* Element-Checklist-Version: 5 */
43 
44 /**
45  * SECTION:element-rtpdec
46  * @title: rtpdec
47  *
48  * A simple RTP session manager used internally by rtspsrc.
49  */
50 
51 /* #define HAVE_RTCP */
52 
53 #include <gst/rtp/gstrtpbuffer.h>
54 
55 #ifdef HAVE_RTCP
56 #include <gst/rtp/gstrtcpbuffer.h>
57 #endif
58 
59 #include "gstrtspelements.h"
60 #include "gstrtpdec.h"
61 #include <stdio.h>
62 
63 GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
64 #define GST_CAT_DEFAULT (rtpdec_debug)
65 
66 /* GstRTPDec signals and args */
67 enum
68 {
69   SIGNAL_REQUEST_PT_MAP,
70   SIGNAL_CLEAR_PT_MAP,
71 
72   SIGNAL_ON_NEW_SSRC,
73   SIGNAL_ON_SSRC_COLLISION,
74   SIGNAL_ON_SSRC_VALIDATED,
75   SIGNAL_ON_BYE_SSRC,
76   SIGNAL_ON_BYE_TIMEOUT,
77   SIGNAL_ON_TIMEOUT,
78   LAST_SIGNAL
79 };
80 
81 #define DEFAULT_LATENCY_MS      200
82 
83 enum
84 {
85   PROP_0,
86   PROP_LATENCY
87 };
88 
89 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
90 GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%u",
91     GST_PAD_SINK,
92     GST_PAD_REQUEST,
93     GST_STATIC_CAPS ("application/x-rtp")
94     );
95 
96 static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
97 GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%u",
98     GST_PAD_SINK,
99     GST_PAD_REQUEST,
100     GST_STATIC_CAPS ("application/x-rtcp")
101     );
102 
103 static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
104 GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%u_%u_%u",
105     GST_PAD_SRC,
106     GST_PAD_SOMETIMES,
107     GST_STATIC_CAPS ("application/x-rtp")
108     );
109 
110 static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
111 GST_STATIC_PAD_TEMPLATE ("rtcp_src_%u",
112     GST_PAD_SRC,
113     GST_PAD_REQUEST,
114     GST_STATIC_CAPS ("application/x-rtcp")
115     );
116 
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);
122 
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);
129 
130 static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent,
131     GstBuffer * buffer);
132 static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent,
133     GstBuffer * buffer);
134 
135 
136 /* Manages the receiving end of the packets.
137  *
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.
140  */
141 struct _GstRTPDecSession
142 {
143   /* session id */
144   gint id;
145   /* the parent bin */
146   GstRTPDec *dec;
147 
148   gboolean active;
149   /* we only support one ssrc and one pt */
150   guint32 ssrc;
151   guint8 pt;
152   GstCaps *caps;
153 
154   /* the pads of the session */
155   GstPad *recv_rtp_sink;
156   GstPad *recv_rtp_src;
157   GstPad *recv_rtcp_sink;
158   GstPad *rtcp_src;
159 };
160 
161 /* find a session with the given id */
162 static GstRTPDecSession *
find_session_by_id(GstRTPDec * rtpdec,gint id)163 find_session_by_id (GstRTPDec * rtpdec, gint id)
164 {
165   GSList *walk;
166 
167   for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
168     GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
169 
170     if (sess->id == id)
171       return sess;
172   }
173   return NULL;
174 }
175 
176 /* create a session with the given id */
177 static GstRTPDecSession *
create_session(GstRTPDec * rtpdec,gint id)178 create_session (GstRTPDec * rtpdec, gint id)
179 {
180   GstRTPDecSession *sess;
181 
182   sess = g_new0 (GstRTPDecSession, 1);
183   sess->id = id;
184   sess->dec = rtpdec;
185   rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
186 
187   return sess;
188 }
189 
190 static void
free_session(GstRTPDecSession * session)191 free_session (GstRTPDecSession * session)
192 {
193   g_free (session);
194 }
195 
196 static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };
197 
198 #define gst_rtp_dec_parent_class parent_class
199 G_DEFINE_TYPE (GstRTPDec, gst_rtp_dec, GST_TYPE_ELEMENT);
200 GST_ELEMENT_REGISTER_DEFINE_WITH_CODE (rtpdec, "rtpdec", GST_RANK_NONE,
201     GST_TYPE_RTP_DEC, rtsp_element_init (plugin));
202 
203 static void
gst_rtp_dec_class_init(GstRTPDecClass * g_class)204 gst_rtp_dec_class_init (GstRTPDecClass * g_class)
205 {
206   GObjectClass *gobject_class;
207   GstElementClass *gstelement_class;
208   GstRTPDecClass *klass;
209 
210   klass = (GstRTPDecClass *) g_class;
211   gobject_class = (GObjectClass *) klass;
212   gstelement_class = (GstElementClass *) klass;
213 
214   GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
215 
216   gobject_class->finalize = gst_rtp_dec_finalize;
217   gobject_class->set_property = gst_rtp_dec_set_property;
218   gobject_class->get_property = gst_rtp_dec_get_property;
219 
220   g_object_class_install_property (gobject_class, PROP_LATENCY,
221       g_param_spec_uint ("latency", "Buffer latency in ms",
222           "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
223           G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
224 
225   /**
226    * GstRTPDec::request-pt-map:
227    * @rtpdec: the object which received the signal
228    * @session: the session
229    * @pt: the pt
230    *
231    * Request the payload type as #GstCaps for @pt in @session.
232    */
233   gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP] =
234       g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
235       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, request_pt_map), NULL,
236       NULL, NULL, GST_TYPE_CAPS, 2, G_TYPE_UINT, G_TYPE_UINT);
237 
238   gst_rtp_dec_signals[SIGNAL_CLEAR_PT_MAP] =
239       g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
240       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, clear_pt_map), NULL,
241       NULL, NULL, G_TYPE_NONE, 0, G_TYPE_NONE);
242 
243   /**
244    * GstRTPDec::on-new-ssrc:
245    * @rtpbin: the object which received the signal
246    * @session: the session
247    * @ssrc: the SSRC
248    *
249    * Notify of a new SSRC that entered @session.
250    */
251   gst_rtp_dec_signals[SIGNAL_ON_NEW_SSRC] =
252       g_signal_new ("on-new-ssrc", G_TYPE_FROM_CLASS (klass),
253       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_new_ssrc), NULL,
254       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
255   /**
256    * GstRTPDec::on-ssrc_collision:
257    * @rtpbin: the object which received the signal
258    * @session: the session
259    * @ssrc: the SSRC
260    *
261    * Notify when we have an SSRC collision
262    */
263   gst_rtp_dec_signals[SIGNAL_ON_SSRC_COLLISION] =
264       g_signal_new ("on-ssrc-collision", G_TYPE_FROM_CLASS (klass),
265       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_collision),
266       NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
267   /**
268    * GstRTPDec::on-ssrc_validated:
269    * @rtpbin: the object which received the signal
270    * @session: the session
271    * @ssrc: the SSRC
272    *
273    * Notify of a new SSRC that became validated.
274    */
275   gst_rtp_dec_signals[SIGNAL_ON_SSRC_VALIDATED] =
276       g_signal_new ("on-ssrc-validated", G_TYPE_FROM_CLASS (klass),
277       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_ssrc_validated),
278       NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
279 
280   /**
281    * GstRTPDec::on-bye-ssrc:
282    * @rtpbin: the object which received the signal
283    * @session: the session
284    * @ssrc: the SSRC
285    *
286    * Notify of an SSRC that became inactive because of a BYE packet.
287    */
288   gst_rtp_dec_signals[SIGNAL_ON_BYE_SSRC] =
289       g_signal_new ("on-bye-ssrc", G_TYPE_FROM_CLASS (klass),
290       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_ssrc), NULL,
291       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
292   /**
293    * GstRTPDec::on-bye-timeout:
294    * @rtpbin: the object which received the signal
295    * @session: the session
296    * @ssrc: the SSRC
297    *
298    * Notify of an SSRC that has timed out because of BYE
299    */
300   gst_rtp_dec_signals[SIGNAL_ON_BYE_TIMEOUT] =
301       g_signal_new ("on-bye-timeout", G_TYPE_FROM_CLASS (klass),
302       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_bye_timeout),
303       NULL, NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
304   /**
305    * GstRTPDec::on-timeout:
306    * @rtpbin: the object which received the signal
307    * @session: the session
308    * @ssrc: the SSRC
309    *
310    * Notify of an SSRC that has timed out
311    */
312   gst_rtp_dec_signals[SIGNAL_ON_TIMEOUT] =
313       g_signal_new ("on-timeout", G_TYPE_FROM_CLASS (klass),
314       G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRTPDecClass, on_timeout), NULL,
315       NULL, NULL, G_TYPE_NONE, 2, G_TYPE_UINT, G_TYPE_UINT);
316 
317   gstelement_class->provide_clock =
318       GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
319   gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
320   gstelement_class->request_new_pad =
321       GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
322   gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
323 
324   /* sink pads */
325   gst_element_class_add_static_pad_template (gstelement_class,
326       &gst_rtp_dec_recv_rtp_sink_template);
327   gst_element_class_add_static_pad_template (gstelement_class,
328       &gst_rtp_dec_recv_rtcp_sink_template);
329   /* src pads */
330   gst_element_class_add_static_pad_template (gstelement_class,
331       &gst_rtp_dec_recv_rtp_src_template);
332   gst_element_class_add_static_pad_template (gstelement_class,
333       &gst_rtp_dec_rtcp_src_template);
334 
335   gst_element_class_set_static_metadata (gstelement_class, "RTP Decoder",
336       "Codec/Parser/Network",
337       "Accepts raw RTP and RTCP packets and sends them forward",
338       "Wim Taymans <wim.taymans@gmail.com>");
339 }
340 
341 static void
gst_rtp_dec_init(GstRTPDec * rtpdec)342 gst_rtp_dec_init (GstRTPDec * rtpdec)
343 {
344   rtpdec->provided_clock = gst_system_clock_obtain ();
345   rtpdec->latency = DEFAULT_LATENCY_MS;
346 
347   GST_OBJECT_FLAG_SET (rtpdec, GST_ELEMENT_FLAG_PROVIDE_CLOCK);
348 }
349 
350 static void
gst_rtp_dec_finalize(GObject * object)351 gst_rtp_dec_finalize (GObject * object)
352 {
353   GstRTPDec *rtpdec;
354 
355   rtpdec = GST_RTP_DEC (object);
356 
357   gst_object_unref (rtpdec->provided_clock);
358   g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
359   g_slist_free (rtpdec->sessions);
360 
361   G_OBJECT_CLASS (parent_class)->finalize (object);
362 }
363 
364 static gboolean
gst_rtp_dec_query_src(GstPad * pad,GstObject * parent,GstQuery * query)365 gst_rtp_dec_query_src (GstPad * pad, GstObject * parent, GstQuery * query)
366 {
367   gboolean res;
368 
369   switch (GST_QUERY_TYPE (query)) {
370     case GST_QUERY_LATENCY:
371     {
372       /* we pretend to be live with a 3 second latency */
373       /* FIXME: Do we really have infinite maximum latency? */
374       gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
375       res = TRUE;
376       break;
377     }
378     default:
379       res = gst_pad_query_default (pad, parent, query);
380       break;
381   }
382   return res;
383 }
384 
385 static GstFlowReturn
gst_rtp_dec_chain_rtp(GstPad * pad,GstObject * parent,GstBuffer * buffer)386 gst_rtp_dec_chain_rtp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
387 {
388   GstFlowReturn res;
389   GstRTPDec *rtpdec;
390   GstRTPDecSession *session;
391   guint32 ssrc;
392   guint8 pt;
393   GstRTPBuffer rtp = { NULL, };
394 
395   rtpdec = GST_RTP_DEC (parent);
396 
397   GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
398 
399   if (!gst_rtp_buffer_map (buffer, GST_MAP_READ, &rtp))
400     goto bad_packet;
401 
402   ssrc = gst_rtp_buffer_get_ssrc (&rtp);
403   pt = gst_rtp_buffer_get_payload_type (&rtp);
404   gst_rtp_buffer_unmap (&rtp);
405 
406   GST_DEBUG_OBJECT (rtpdec, "SSRC %08x, PT %d", ssrc, pt);
407 
408   /* find session */
409   session = gst_pad_get_element_private (pad);
410 
411   /* see if we have the pad */
412   if (!session->active) {
413     GstPadTemplate *templ;
414     GstElementClass *klass;
415     gchar *name;
416     GstCaps *caps;
417     GValue ret = { 0 };
418     GValue args[3] = { {0}
419     , {0}
420     , {0}
421     };
422 
423     GST_DEBUG_OBJECT (rtpdec, "creating stream");
424 
425     session->ssrc = ssrc;
426     session->pt = pt;
427 
428     /* get pt map */
429     g_value_init (&args[0], GST_TYPE_ELEMENT);
430     g_value_set_object (&args[0], rtpdec);
431     g_value_init (&args[1], G_TYPE_UINT);
432     g_value_set_uint (&args[1], session->id);
433     g_value_init (&args[2], G_TYPE_UINT);
434     g_value_set_uint (&args[2], pt);
435 
436     g_value_init (&ret, GST_TYPE_CAPS);
437     g_value_set_boxed (&ret, NULL);
438 
439     g_signal_emitv (args, gst_rtp_dec_signals[SIGNAL_REQUEST_PT_MAP], 0, &ret);
440 
441     caps = (GstCaps *) g_value_get_boxed (&ret);
442 
443     name = g_strdup_printf ("recv_rtp_src_%u_%u_%u", session->id, ssrc, pt);
444     klass = GST_ELEMENT_GET_CLASS (rtpdec);
445     templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%u_%u_%u");
446     session->recv_rtp_src = gst_pad_new_from_template (templ, name);
447     g_free (name);
448 
449     gst_pad_set_caps (session->recv_rtp_src, caps);
450 
451     gst_pad_set_element_private (session->recv_rtp_src, session);
452     gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
453     gst_pad_set_active (session->recv_rtp_src, TRUE);
454     gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
455 
456     session->active = TRUE;
457   }
458 
459   res = gst_pad_push (session->recv_rtp_src, buffer);
460 
461   return res;
462 
463 bad_packet:
464   {
465     GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
466         ("RTP packet did not validate, dropping"));
467     gst_buffer_unref (buffer);
468     return GST_FLOW_OK;
469   }
470 }
471 
472 static GstFlowReturn
gst_rtp_dec_chain_rtcp(GstPad * pad,GstObject * parent,GstBuffer * buffer)473 gst_rtp_dec_chain_rtcp (GstPad * pad, GstObject * parent, GstBuffer * buffer)
474 {
475   GstRTPDec *src;
476 
477 #ifdef HAVE_RTCP
478   gboolean valid;
479   GstRTCPPacket packet;
480   gboolean more;
481 #endif
482 
483   src = GST_RTP_DEC (parent);
484 
485   GST_DEBUG_OBJECT (src, "got rtcp packet");
486 
487 #ifdef HAVE_RTCP
488   valid = gst_rtcp_buffer_validate (buffer);
489   if (!valid)
490     goto bad_packet;
491 
492   /* position on first packet */
493   more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
494   while (more) {
495     switch (gst_rtcp_packet_get_type (&packet)) {
496       case GST_RTCP_TYPE_SR:
497       {
498         guint32 ssrc, rtptime, packet_count, octet_count;
499         guint64 ntptime;
500         guint count, i;
501 
502         gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
503             &packet_count, &octet_count);
504 
505         GST_DEBUG_OBJECT (src,
506             "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
507             ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
508             octet_count);
509 
510         count = gst_rtcp_packet_get_rb_count (&packet);
511         for (i = 0; i < count; i++) {
512           guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
513           guint8 fractionlost;
514           gint32 packetslost;
515 
516           gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
517               &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
518 
519           GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
520               ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
521               packetslost, exthighestseq, jitter, lsr, dlsr);
522         }
523         break;
524       }
525       case GST_RTCP_TYPE_RR:
526       {
527         guint32 ssrc;
528         guint count, i;
529 
530         ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
531 
532         GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
533 
534         count = gst_rtcp_packet_get_rb_count (&packet);
535         for (i = 0; i < count; i++) {
536           guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
537           guint8 fractionlost;
538           gint32 packetslost;
539 
540           gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
541               &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
542 
543           GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
544               ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
545               packetslost, exthighestseq, jitter, lsr, dlsr);
546         }
547         break;
548       }
549       case GST_RTCP_TYPE_SDES:
550       {
551         guint chunks, i, j;
552         gboolean more_chunks, more_items;
553 
554         chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
555         GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
556 
557         more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
558         i = 0;
559         while (more_chunks) {
560           guint32 ssrc;
561 
562           ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
563 
564           GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
565 
566           more_items = gst_rtcp_packet_sdes_first_item (&packet);
567           j = 0;
568           while (more_items) {
569             GstRTCPSDESType type;
570             guint8 len;
571             gchar *data;
572 
573             gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
574 
575             GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
576                 type, len, data);
577 
578             more_items = gst_rtcp_packet_sdes_next_item (&packet);
579             j++;
580           }
581           more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
582           i++;
583         }
584         break;
585       }
586       case GST_RTCP_TYPE_BYE:
587       {
588         guint count, i;
589         gchar *reason;
590 
591         reason = gst_rtcp_packet_bye_get_reason (&packet);
592         GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
593             GST_STR_NULL (reason));
594         g_free (reason);
595 
596         count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
597         for (i = 0; i < count; i++) {
598           guint32 ssrc;
599 
600 
601           ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
602 
603           GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
604         }
605         break;
606       }
607       case GST_RTCP_TYPE_APP:
608         GST_DEBUG_OBJECT (src, "got APP packet");
609         break;
610       default:
611         GST_WARNING_OBJECT (src, "got unknown RTCP packet");
612         break;
613     }
614     more = gst_rtcp_packet_move_to_next (&packet);
615   }
616   gst_buffer_unref (buffer);
617   return GST_FLOW_OK;
618 
619 bad_packet:
620   {
621     GST_WARNING_OBJECT (src, "got invalid RTCP packet");
622     gst_buffer_unref (buffer);
623     return GST_FLOW_OK;
624   }
625 #else
626   gst_buffer_unref (buffer);
627   return GST_FLOW_OK;
628 #endif
629 }
630 
631 static void
gst_rtp_dec_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)632 gst_rtp_dec_set_property (GObject * object, guint prop_id,
633     const GValue * value, GParamSpec * pspec)
634 {
635   GstRTPDec *src;
636 
637   src = GST_RTP_DEC (object);
638 
639   switch (prop_id) {
640     case PROP_LATENCY:
641       src->latency = g_value_get_uint (value);
642       break;
643     default:
644       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
645       break;
646   }
647 }
648 
649 static void
gst_rtp_dec_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)650 gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
651     GParamSpec * pspec)
652 {
653   GstRTPDec *src;
654 
655   src = GST_RTP_DEC (object);
656 
657   switch (prop_id) {
658     case PROP_LATENCY:
659       g_value_set_uint (value, src->latency);
660       break;
661     default:
662       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
663       break;
664   }
665 }
666 
667 static GstClock *
gst_rtp_dec_provide_clock(GstElement * element)668 gst_rtp_dec_provide_clock (GstElement * element)
669 {
670   GstRTPDec *rtpdec;
671 
672   rtpdec = GST_RTP_DEC (element);
673 
674   return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
675 }
676 
677 static GstStateChangeReturn
gst_rtp_dec_change_state(GstElement * element,GstStateChange transition)678 gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
679 {
680   GstStateChangeReturn ret;
681 
682   switch (transition) {
683     default:
684       break;
685   }
686 
687   ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
688 
689   switch (transition) {
690     case GST_STATE_CHANGE_READY_TO_PAUSED:
691     case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
692       /* we're NO_PREROLL when going to PAUSED */
693       ret = GST_STATE_CHANGE_NO_PREROLL;
694       break;
695     default:
696       break;
697   }
698 
699   return ret;
700 }
701 
702 /* Create a pad for receiving RTP for the session in @name
703  */
704 static GstPad *
create_recv_rtp(GstRTPDec * rtpdec,GstPadTemplate * templ,const gchar * name)705 create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
706 {
707   guint sessid;
708   GstRTPDecSession *session;
709 
710   /* first get the session number */
711   if (name == NULL || sscanf (name, "recv_rtp_sink_%u", &sessid) != 1)
712     goto no_name;
713 
714   GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
715 
716   /* get or create session */
717   session = find_session_by_id (rtpdec, sessid);
718   if (!session) {
719     GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
720     /* create session now */
721     session = create_session (rtpdec, sessid);
722     if (session == NULL)
723       goto create_error;
724   }
725   /* check if pad was requested */
726   if (session->recv_rtp_sink != NULL)
727     goto existed;
728 
729   GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
730 
731   session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
732   gst_pad_set_element_private (session->recv_rtp_sink, session);
733   gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
734   gst_pad_set_active (session->recv_rtp_sink, TRUE);
735   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
736 
737   return session->recv_rtp_sink;
738 
739   /* ERRORS */
740 no_name:
741   {
742     g_warning ("rtpdec: invalid name given");
743     return NULL;
744   }
745 create_error:
746   {
747     /* create_session already warned */
748     return NULL;
749   }
750 existed:
751   {
752     g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
753     return NULL;
754   }
755 }
756 
757 /* Create a pad for receiving RTCP for the session in @name
758  */
759 static GstPad *
create_recv_rtcp(GstRTPDec * rtpdec,GstPadTemplate * templ,const gchar * name)760 create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
761     const gchar * name)
762 {
763   guint sessid;
764   GstRTPDecSession *session;
765 
766   /* first get the session number */
767   if (name == NULL || sscanf (name, "recv_rtcp_sink_%u", &sessid) != 1)
768     goto no_name;
769 
770   GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
771 
772   /* get the session, it must exist or we error */
773   session = find_session_by_id (rtpdec, sessid);
774   if (!session)
775     goto no_session;
776 
777   /* check if pad was requested */
778   if (session->recv_rtcp_sink != NULL)
779     goto existed;
780 
781   GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
782 
783   session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
784   gst_pad_set_element_private (session->recv_rtp_sink, session);
785   gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
786   gst_pad_set_active (session->recv_rtcp_sink, TRUE);
787   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
788 
789   return session->recv_rtcp_sink;
790 
791   /* ERRORS */
792 no_name:
793   {
794     g_warning ("rtpdec: invalid name given");
795     return NULL;
796   }
797 no_session:
798   {
799     g_warning ("rtpdec: no session with id %d", sessid);
800     return NULL;
801   }
802 existed:
803   {
804     g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
805         sessid);
806     return NULL;
807   }
808 }
809 
810 /* Create a pad for sending RTCP for the session in @name
811  */
812 static GstPad *
create_rtcp(GstRTPDec * rtpdec,GstPadTemplate * templ,const gchar * name)813 create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
814 {
815   guint sessid;
816   GstRTPDecSession *session;
817 
818   /* first get the session number */
819   if (name == NULL || sscanf (name, "rtcp_src_%u", &sessid) != 1)
820     goto no_name;
821 
822   /* get or create session */
823   session = find_session_by_id (rtpdec, sessid);
824   if (!session)
825     goto no_session;
826 
827   /* check if pad was requested */
828   if (session->rtcp_src != NULL)
829     goto existed;
830 
831   session->rtcp_src = gst_pad_new_from_template (templ, name);
832   gst_pad_set_active (session->rtcp_src, TRUE);
833   gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
834 
835   return session->rtcp_src;
836 
837   /* ERRORS */
838 no_name:
839   {
840     g_warning ("rtpdec: invalid name given");
841     return NULL;
842   }
843 no_session:
844   {
845     g_warning ("rtpdec: session with id %d does not exist", sessid);
846     return NULL;
847   }
848 existed:
849   {
850     g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
851     return NULL;
852   }
853 }
854 
855 /*
856  */
857 static GstPad *
gst_rtp_dec_request_new_pad(GstElement * element,GstPadTemplate * templ,const gchar * name,const GstCaps * caps)858 gst_rtp_dec_request_new_pad (GstElement * element,
859     GstPadTemplate * templ, const gchar * name, const GstCaps * caps)
860 {
861   GstRTPDec *rtpdec;
862   GstElementClass *klass;
863   GstPad *result;
864 
865   g_return_val_if_fail (templ != NULL, NULL);
866   g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
867 
868   rtpdec = GST_RTP_DEC (element);
869   klass = GST_ELEMENT_GET_CLASS (element);
870 
871   /* figure out the template */
872   if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%u")) {
873     result = create_recv_rtp (rtpdec, templ, name);
874   } else if (templ == gst_element_class_get_pad_template (klass,
875           "recv_rtcp_sink_%u")) {
876     result = create_recv_rtcp (rtpdec, templ, name);
877   } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%u")) {
878     result = create_rtcp (rtpdec, templ, name);
879   } else
880     goto wrong_template;
881 
882   return result;
883 
884   /* ERRORS */
885 wrong_template:
886   {
887     g_warning ("rtpdec: this is not our template");
888     return NULL;
889   }
890 }
891 
892 static void
gst_rtp_dec_release_pad(GstElement * element,GstPad * pad)893 gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
894 {
895 }
896