gst/rtsp/: Morph RTPDec into something compatible with RTPBin as a fallback.
Original commit message from CVS:
* gst/rtsp/Makefile.am:
* gst/rtsp/gstrtpdec.c: (find_session_by_id), (create_session),
(free_session), (gst_rtp_dec_base_init), (gst_rtp_dec_class_init),
(gst_rtp_dec_init), (gst_rtp_dec_finalize),
(gst_rtp_dec_query_src), (gst_rtp_dec_chain_rtp),
(gst_rtp_dec_chain_rtcp), (gst_rtp_dec_set_property),
(gst_rtp_dec_get_property), (gst_rtp_dec_provide_clock),
(gst_rtp_dec_change_state), (create_recv_rtp), (create_recv_rtcp),
(create_rtcp), (gst_rtp_dec_request_new_pad),
(gst_rtp_dec_release_pad):
* gst/rtsp/gstrtpdec.h:
* gst/rtsp/gstrtsp.c: (plugin_init):
Morph RTPDec into something compatible with RTPBin as a fallback.
Various other style fixes.
* gst/rtsp/gstrtspsrc.c: (find_stream_by_id),
(find_stream_by_udpsrc), (gst_rtspsrc_stream_free),
(gst_rtspsrc_cleanup), (gst_rtspsrc_media_to_caps),
(new_session_pad), (gst_rtspsrc_stream_configure_transport),
(gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
(gst_rtspsrc_loop_udp), (gst_rtspsrc_setup_auth),
(gst_rtspsrc_handle_message), (gst_rtspsrc_change_state):
* gst/rtsp/gstrtspsrc.h:
Implement RTPBin session manager handling.
Don't try to add empty properties to caps.
Implement fallback session manager, handling.
Don't combine errors from RTCP streams, just ignore them.
* gst/rtsp/rtsptransport.c: (rtsp_transport_get_manager):
* gst/rtsp/rtsptransport.h:
Implement fallback session manager.
Make RTPBin the default one when available.
diff --git a/gst/rtsp/gstrtpdec.c b/gst/rtsp/gstrtpdec.c
index 9320f7d..ed119a5 100644
--- a/gst/rtsp/gstrtpdec.c
+++ b/gst/rtsp/gstrtpdec.c
@@ -53,6 +53,14 @@
* Last reviewed on 2006-06-20 (0.10.4)
*/
+/* #define HAVE_RTCP */
+
+#include <gst/rtp/gstrtpbuffer.h>
+
+#ifdef HAVE_RTCP
+#include <gst/rtp/gstrtcpbuffer.h>
+#endif
+
#include "gstrtpdec.h"
GST_DEBUG_CATEGORY_STATIC (rtpdec_debug);
@@ -68,89 +76,144 @@
/* GstRTPDec signals and args */
enum
{
- /* FILL ME */
LAST_SIGNAL
};
enum
{
- ARG_0,
- ARG_SKIP
- /* FILL ME */
+ PROP_0,
};
-static GstStaticPadTemplate gst_rtpdec_src_rtp_template =
-GST_STATIC_PAD_TEMPLATE ("srcrtp",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_sink_%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtp")
);
-static GstStaticPadTemplate gst_rtpdec_src_rtcp_template =
-GST_STATIC_PAD_TEMPLATE ("srcrtcp",
- GST_PAD_SRC,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtcp_sink_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtcp_sink_%d",
+ GST_PAD_SINK,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtcp")
);
-static GstStaticPadTemplate gst_rtpdec_sink_rtp_template =
-GST_STATIC_PAD_TEMPLATE ("sinkrtp",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_recv_rtp_src_template =
+GST_STATIC_PAD_TEMPLATE ("recv_rtp_src_%d_%d_%d",
+ GST_PAD_SRC,
+ GST_PAD_SOMETIMES,
GST_STATIC_CAPS ("application/x-rtp")
);
-static GstStaticPadTemplate gst_rtpdec_sink_rtcp_template =
-GST_STATIC_PAD_TEMPLATE ("sinkrtcp",
- GST_PAD_SINK,
- GST_PAD_ALWAYS,
+static GstStaticPadTemplate gst_rtp_dec_rtcp_src_template =
+GST_STATIC_PAD_TEMPLATE ("rtcp_src_%d",
+ GST_PAD_SRC,
+ GST_PAD_REQUEST,
GST_STATIC_CAPS ("application/x-rtcp")
);
-static void gst_rtpdec_class_init (gpointer g_class);
-static void gst_rtpdec_init (GstRTPDec * rtpdec);
-
-static GstCaps *gst_rtpdec_getcaps (GstPad * pad);
-static GstFlowReturn gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer);
-static GstFlowReturn gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
-
-static void gst_rtpdec_set_property (GObject * object,
+static void gst_rtp_dec_finalize (GObject * object);
+static void gst_rtp_dec_set_property (GObject * object,
guint prop_id, const GValue * value, GParamSpec * pspec);
-static void gst_rtpdec_get_property (GObject * object,
+static void gst_rtp_dec_get_property (GObject * object,
guint prop_id, GValue * value, GParamSpec * pspec);
-static GstStateChangeReturn gst_rtpdec_change_state (GstElement * element,
+static GstClock *gst_rtp_dec_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_rtp_dec_change_state (GstElement * element,
GstStateChange transition);
+static GstPad *gst_rtp_dec_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name);
+static void gst_rtp_dec_release_pad (GstElement * element, GstPad * pad);
-static GstElementClass *parent_class = NULL;
+static GstFlowReturn gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer);
+static GstFlowReturn gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer);
-/*static guint gst_rtpdec_signals[LAST_SIGNAL] = { 0 };*/
-GType
-gst_rtpdec_get_type (void)
+/* Manages the receiving end of the packets.
+ *
+ * There is one such structure for each RTP session (audio/video/...).
+ * We get the RTP/RTCP packets and stuff them into the session manager.
+ */
+struct _GstRTPDecSession
{
- static GType rtpdec_type = 0;
+ /* session id */
+ gint id;
+ /* the parent bin */
+ GstRTPDec *dec;
- if (!rtpdec_type) {
- static const GTypeInfo rtpdec_info = {
- sizeof (GstRTPDecClass), NULL,
- NULL,
- (GClassInitFunc) gst_rtpdec_class_init,
- NULL,
- NULL,
- sizeof (GstRTPDec),
- 0,
- (GInstanceInitFunc) gst_rtpdec_init,
- };
+ gboolean active;
+ /* we only support one ssrc and one pt */
+ guint32 ssrc;
+ guint8 pt;
+ GstCaps *caps;
- rtpdec_type =
- g_type_register_static (GST_TYPE_ELEMENT, "GstRTPDec", &rtpdec_info, 0);
+ /* the pads of the session */
+ GstPad *recv_rtp_sink;
+ GstPad *recv_rtp_src;
+ GstPad *recv_rtcp_sink;
+ GstPad *rtcp_src;
+};
+
+/* find a session with the given id */
+static GstRTPDecSession *
+find_session_by_id (GstRTPDec * rtpdec, gint id)
+{
+ GSList *walk;
+
+ for (walk = rtpdec->sessions; walk; walk = g_slist_next (walk)) {
+ GstRTPDecSession *sess = (GstRTPDecSession *) walk->data;
+
+ if (sess->id == id)
+ return sess;
}
- return rtpdec_type;
+ return NULL;
+}
+
+/* create a session with the given id */
+static GstRTPDecSession *
+create_session (GstRTPDec * rtpdec, gint id)
+{
+ GstRTPDecSession *sess;
+
+ sess = g_new0 (GstRTPDecSession, 1);
+ sess->id = id;
+ sess->dec = rtpdec;
+ rtpdec->sessions = g_slist_prepend (rtpdec->sessions, sess);
+
+ return sess;
}
static void
-gst_rtpdec_class_init (gpointer g_class)
+free_session (GstRTPDecSession * session)
+{
+ g_free (session);
+}
+
+/*static guint gst_rtp_dec_signals[LAST_SIGNAL] = { 0 };*/
+
+GST_BOILERPLATE (GstRTPDec, gst_rtp_dec, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_rtp_dec_base_init (gpointer klass)
+{
+ GstElementClass *element_class = GST_ELEMENT_CLASS (klass);
+
+ /* sink pads */
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_sink_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtcp_sink_template));
+ /* src pads */
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_recv_rtp_src_template));
+ gst_element_class_add_pad_template (element_class,
+ gst_static_pad_template_get (&gst_rtp_dec_rtcp_src_template));
+
+ gst_element_class_set_details (element_class, &rtpdec_details);
+}
+
+static void
+gst_rtp_dec_class_init (GstRTPDecClass * g_class)
{
GObjectClass *gobject_class;
GstElementClass *gstelement_class;
@@ -160,157 +223,324 @@
gobject_class = (GObjectClass *) klass;
gstelement_class = (GstElementClass *) klass;
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_src_rtp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_src_rtcp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_sink_rtp_template));
- gst_element_class_add_pad_template (gstelement_class,
- gst_static_pad_template_get (&gst_rtpdec_sink_rtcp_template));
- gst_element_class_set_details (gstelement_class, &rtpdec_details);
+ gobject_class->finalize = gst_rtp_dec_finalize;
+ gobject_class->set_property = gst_rtp_dec_set_property;
+ gobject_class->get_property = gst_rtp_dec_get_property;
- gobject_class->set_property = gst_rtpdec_set_property;
- gobject_class->get_property = gst_rtpdec_get_property;
-
- /* FIXME, this is unused and probably copied from somewhere */
- g_object_class_install_property (G_OBJECT_CLASS (klass), ARG_SKIP,
- g_param_spec_int ("skip", "Skip", "skip (unused)", G_MININT, G_MAXINT, 0,
- G_PARAM_READWRITE));
-
- parent_class = g_type_class_peek_parent (klass);
-
- gstelement_class->change_state = gst_rtpdec_change_state;
+ gstelement_class->provide_clock =
+ GST_DEBUG_FUNCPTR (gst_rtp_dec_provide_clock);
+ gstelement_class->change_state = GST_DEBUG_FUNCPTR (gst_rtp_dec_change_state);
+ gstelement_class->request_new_pad =
+ GST_DEBUG_FUNCPTR (gst_rtp_dec_request_new_pad);
+ gstelement_class->release_pad = GST_DEBUG_FUNCPTR (gst_rtp_dec_release_pad);
GST_DEBUG_CATEGORY_INIT (rtpdec_debug, "rtpdec", 0, "RTP decoder");
}
static void
-gst_rtpdec_init (GstRTPDec * rtpdec)
+gst_rtp_dec_init (GstRTPDec * rtpdec, GstRTPDecClass * klass)
{
- /* the input rtp pad */
- rtpdec->sink_rtp =
- gst_pad_new_from_static_template (&gst_rtpdec_sink_rtp_template,
- "sinkrtp");
- gst_pad_set_getcaps_function (rtpdec->sink_rtp, gst_rtpdec_getcaps);
- gst_pad_set_chain_function (rtpdec->sink_rtp, gst_rtpdec_chain_rtp);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtp);
-
- /* the input rtcp pad */
- rtpdec->sink_rtcp =
- gst_pad_new_from_static_template (&gst_rtpdec_sink_rtcp_template,
- "sinkrtcp");
- gst_pad_set_chain_function (rtpdec->sink_rtcp, gst_rtpdec_chain_rtcp);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->sink_rtcp);
-
- /* the output rtp pad */
- rtpdec->src_rtp =
- gst_pad_new_from_static_template (&gst_rtpdec_src_rtp_template, "srcrtp");
- gst_pad_set_getcaps_function (rtpdec->src_rtp, gst_rtpdec_getcaps);
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtp);
-
- /* the output rtcp pad */
- rtpdec->src_rtcp =
- gst_pad_new_from_static_template (&gst_rtpdec_src_rtcp_template,
- "srcrtcp");
- gst_element_add_pad (GST_ELEMENT (rtpdec), rtpdec->src_rtcp);
-}
-
-static GstCaps *
-gst_rtpdec_getcaps (GstPad * pad)
-{
- GstRTPDec *src;
- GstPad *other;
- GstCaps *caps;
- const GstCaps *templ;
-
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
-
- other = (pad == src->src_rtp ? src->sink_rtp : src->src_rtp);
-
- caps = gst_pad_peer_get_caps (other);
-
- templ = gst_pad_get_pad_template_caps (pad);
- if (caps == NULL) {
- GST_DEBUG_OBJECT (src, "copy template");
- caps = gst_caps_copy (templ);
- } else {
- GstCaps *intersect;
-
- GST_DEBUG_OBJECT (src, "intersect with template");
-
- intersect = gst_caps_intersect (caps, templ);
- gst_caps_unref (caps);
-
- caps = intersect;
- }
-
- return caps;
-}
-
-static GstFlowReturn
-gst_rtpdec_chain_rtp (GstPad * pad, GstBuffer * buffer)
-{
- GstRTPDec *src;
-
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
-
- GST_DEBUG_OBJECT (src, "got rtp packet");
- return gst_pad_push (src->src_rtp, buffer);
-}
-
-static GstFlowReturn
-gst_rtpdec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
-{
- GstRTPDec *src;
-
- src = GST_RTPDEC (GST_PAD_PARENT (pad));
-
- GST_DEBUG_OBJECT (src, "got rtcp packet");
-
- gst_buffer_unref (buffer);
- return GST_FLOW_OK;
+ rtpdec->provided_clock = gst_system_clock_obtain ();
}
static void
-gst_rtpdec_set_property (GObject * object, guint prop_id,
+gst_rtp_dec_finalize (GObject * object)
+{
+ GstRTPDec *rtpdec;
+
+ rtpdec = GST_RTP_DEC (object);
+
+ g_slist_foreach (rtpdec->sessions, (GFunc) free_session, NULL);
+ g_slist_free (rtpdec->sessions);
+
+ G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rtp_dec_query_src (GstPad * pad, GstQuery * query)
+{
+ GstRTPDec *rtpdec;
+ gboolean res;
+
+ rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
+
+ switch (GST_QUERY_TYPE (query)) {
+ case GST_QUERY_LATENCY:
+ {
+ /* we pretend to be live with a 3 second latency */
+ gst_query_set_latency (query, TRUE, 3 * GST_SECOND, -1);
+ res = TRUE;
+ break;
+ }
+ default:
+ res = gst_pad_query_default (pad, query);
+ break;
+ }
+ return res;
+}
+
+static GstFlowReturn
+gst_rtp_dec_chain_rtp (GstPad * pad, GstBuffer * buffer)
+{
+ GstFlowReturn res;
+ GstRTPDec *rtpdec;
+ GstRTPDecSession *session;
+ guint32 ssrc;
+ guint8 pt;
+
+ rtpdec = GST_RTP_DEC (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (rtpdec, "got rtp packet");
+
+ if (!gst_rtp_buffer_validate (buffer))
+ goto bad_packet;
+
+ ssrc = gst_rtp_buffer_get_ssrc (buffer);
+ pt = gst_rtp_buffer_get_payload_type (buffer);
+
+ GST_DEBUG_OBJECT (rtpdec, "SSRC %d, PT %d", ssrc, pt);
+
+ /* find session */
+ session = gst_pad_get_element_private (pad);
+
+ /* see if we have the pad */
+ if (!session->active) {
+ GstPadTemplate *templ;
+ GstElementClass *klass;
+ gchar *name;
+
+ GST_DEBUG_OBJECT (rtpdec, "creating stream");
+
+ session->ssrc = ssrc;
+ session->pt = pt;
+
+ name = g_strdup_printf ("recv_rtp_src_%d_%u_%d", session->id, ssrc, pt);
+ klass = GST_ELEMENT_GET_CLASS (rtpdec);
+ templ = gst_element_class_get_pad_template (klass, "recv_rtp_src_%d_%d_%d");
+ session->recv_rtp_src = gst_pad_new_from_template (templ, name);
+ g_free (name);
+ gst_pad_set_element_private (session->recv_rtp_src, session);
+ gst_pad_set_query_function (session->recv_rtp_src, gst_rtp_dec_query_src);
+ gst_pad_set_active (session->recv_rtp_src, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_src);
+
+ session->active = TRUE;
+ }
+
+ res = gst_pad_push (session->recv_rtp_src, buffer);
+
+ return res;
+
+bad_packet:
+ {
+ GST_ELEMENT_WARNING (rtpdec, STREAM, DECODE, (NULL),
+ ("RTP packet did not validate, dropping"));
+ return GST_FLOW_OK;
+ }
+}
+
+static GstFlowReturn
+gst_rtp_dec_chain_rtcp (GstPad * pad, GstBuffer * buffer)
+{
+ GstRTPDec *src;
+
+#ifdef HAVE_RTCP
+ gboolean valid;
+ GstRTCPPacket packet;
+ gboolean more;
+#endif
+
+ src = GST_RTP_DEC (GST_PAD_PARENT (pad));
+
+ GST_DEBUG_OBJECT (src, "got rtcp packet");
+
+#ifdef HAVE_RTCP
+ valid = gst_rtcp_buffer_validate (buffer);
+ if (!valid)
+ goto bad_packet;
+
+ /* position on first packet */
+ more = gst_rtcp_buffer_get_first_packet (buffer, &packet);
+ while (more) {
+ switch (gst_rtcp_packet_get_type (&packet)) {
+ case GST_RTCP_TYPE_SR:
+ {
+ guint32 ssrc, rtptime, packet_count, octet_count;
+ guint64 ntptime;
+ guint count, i;
+
+ gst_rtcp_packet_sr_get_sender_info (&packet, &ssrc, &ntptime, &rtptime,
+ &packet_count, &octet_count);
+
+ GST_DEBUG_OBJECT (src,
+ "got SR packet: SSRC %08x, NTP %" G_GUINT64_FORMAT
+ ", RTP %u, PC %u, OC %u", ssrc, ntptime, rtptime, packet_count,
+ octet_count);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_RR:
+ {
+ guint32 ssrc;
+ guint count, i;
+
+ ssrc = gst_rtcp_packet_rr_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "got RR packet: SSRC %08x", ssrc);
+
+ count = gst_rtcp_packet_get_rb_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc, exthighestseq, jitter, lsr, dlsr;
+ guint8 fractionlost;
+ gint32 packetslost;
+
+ gst_rtcp_packet_get_rb (&packet, i, &ssrc, &fractionlost,
+ &packetslost, &exthighestseq, &jitter, &lsr, &dlsr);
+
+ GST_DEBUG_OBJECT (src, "got RB packet %d: SSRC %08x, FL %u"
+ ", PL %u, HS %u, JITTER %u, LSR %u, DLSR %u", ssrc, fractionlost,
+ packetslost, exthighestseq, jitter, lsr, dlsr);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_SDES:
+ {
+ guint chunks, i, j;
+ gboolean more_chunks, more_items;
+
+ chunks = gst_rtcp_packet_sdes_get_chunk_count (&packet);
+ GST_DEBUG_OBJECT (src, "got SDES packet with %d chunks", chunks);
+
+ more_chunks = gst_rtcp_packet_sdes_first_chunk (&packet);
+ i = 0;
+ while (more_chunks) {
+ guint32 ssrc;
+
+ ssrc = gst_rtcp_packet_sdes_get_ssrc (&packet);
+
+ GST_DEBUG_OBJECT (src, "chunk %d, SSRC %08x", i, ssrc);
+
+ more_items = gst_rtcp_packet_sdes_first_item (&packet);
+ j = 0;
+ while (more_items) {
+ GstRTCPSDESType type;
+ guint8 len;
+ gchar *data;
+
+ gst_rtcp_packet_sdes_get_item (&packet, &type, &len, &data);
+
+ GST_DEBUG_OBJECT (src, "item %d, type %d, len %d, data %s", j,
+ type, len, data);
+
+ more_items = gst_rtcp_packet_sdes_next_item (&packet);
+ j++;
+ }
+ more_chunks = gst_rtcp_packet_sdes_next_chunk (&packet);
+ i++;
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_BYE:
+ {
+ guint count, i;
+ gchar *reason;
+
+ reason = gst_rtcp_packet_bye_get_reason (&packet);
+ GST_DEBUG_OBJECT (src, "got BYE packet (reason: %s)",
+ GST_STR_NULL (reason));
+ g_free (reason);
+
+ count = gst_rtcp_packet_bye_get_ssrc_count (&packet);
+ for (i = 0; i < count; i++) {
+ guint32 ssrc;
+
+
+ ssrc = gst_rtcp_packet_bye_get_nth_ssrc (&packet, i);
+
+ GST_DEBUG_OBJECT (src, "SSRC: %08x", ssrc);
+ }
+ break;
+ }
+ case GST_RTCP_TYPE_APP:
+ GST_DEBUG_OBJECT (src, "got APP packet");
+ break;
+ default:
+ GST_WARNING_OBJECT (src, "got unknown RTCP packet");
+ break;
+ }
+ more = gst_rtcp_packet_move_to_next (&packet);
+ }
+ gst_buffer_unref (buffer);
+ return GST_FLOW_OK;
+
+bad_packet:
+ {
+ GST_WARNING_OBJECT (src, "got invalid RTCP packet");
+ return GST_FLOW_OK;
+ }
+#else
+ return GST_FLOW_OK;
+#endif
+}
+
+static void
+gst_rtp_dec_set_property (GObject * object, guint prop_id,
const GValue * value, GParamSpec * pspec)
{
GstRTPDec *src;
- src = GST_RTPDEC (object);
+ src = GST_RTP_DEC (object);
switch (prop_id) {
- case ARG_SKIP:
- break;
default:
break;
}
}
static void
-gst_rtpdec_get_property (GObject * object, guint prop_id, GValue * value,
+gst_rtp_dec_get_property (GObject * object, guint prop_id, GValue * value,
GParamSpec * pspec)
{
GstRTPDec *src;
- src = GST_RTPDEC (object);
+ src = GST_RTP_DEC (object);
switch (prop_id) {
- case ARG_SKIP:
- break;
default:
break;
}
}
+static GstClock *
+gst_rtp_dec_provide_clock (GstElement * element)
+{
+ GstRTPDec *rtpdec;
+
+ rtpdec = GST_RTP_DEC (element);
+
+ return GST_CLOCK_CAST (gst_object_ref (rtpdec->provided_clock));
+}
+
static GstStateChangeReturn
-gst_rtpdec_change_state (GstElement * element, GstStateChange transition)
+gst_rtp_dec_change_state (GstElement * element, GstStateChange transition)
{
GstStateChangeReturn ret;
GstRTPDec *rtpdec;
- rtpdec = GST_RTPDEC (element);
+ rtpdec = GST_RTP_DEC (element);
switch (transition) {
default:
@@ -322,6 +552,7 @@
switch (transition) {
case GST_STATE_CHANGE_READY_TO_PAUSED:
case GST_STATE_CHANGE_PLAYING_TO_PAUSED:
+ /* we're NO_PREROLL when going to PAUSED */
ret = GST_STATE_CHANGE_NO_PREROLL;
break;
default:
@@ -330,3 +561,198 @@
return ret;
}
+
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+ /* get or create session */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session) {
+ GST_DEBUG_OBJECT (rtpdec, "creating session %d", sessid);
+ /* create session now */
+ session = create_session (rtpdec, sessid);
+ if (session == NULL)
+ goto create_error;
+ }
+ /* check if pad was requested */
+ if (session->recv_rtp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rtpdec, "getting RTP sink pad");
+
+ session->recv_rtp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_chain_function (session->recv_rtp_sink, gst_rtp_dec_chain_rtp);
+ gst_pad_set_active (session->recv_rtp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtp_sink);
+
+ return session->recv_rtp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+create_error:
+ {
+ /* create_session already warned */
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: recv_rtp pad already requested for session %d", sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for receiving RTCP for the session in @name
+ */
+static GstPad *
+create_recv_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ,
+ const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
+ goto no_name;
+
+ GST_DEBUG_OBJECT (rtpdec, "finding session %d", sessid);
+
+ /* get the session, it must exist or we error */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->recv_rtcp_sink != NULL)
+ goto existed;
+
+ GST_DEBUG_OBJECT (rtpdec, "getting RTCP sink pad");
+
+ session->recv_rtcp_sink = gst_pad_new_from_template (templ, name);
+ gst_pad_set_element_private (session->recv_rtp_sink, session);
+ gst_pad_set_chain_function (session->recv_rtcp_sink, gst_rtp_dec_chain_rtcp);
+ gst_pad_set_active (session->recv_rtcp_sink, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->recv_rtcp_sink);
+
+ return session->recv_rtcp_sink;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rtpdec: no session with id %d", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: recv_rtcp pad already requested for session %d",
+ sessid);
+ return NULL;
+ }
+}
+
+/* Create a pad for sending RTCP for the session in @name
+ */
+static GstPad *
+create_rtcp (GstRTPDec * rtpdec, GstPadTemplate * templ, const gchar * name)
+{
+ guint sessid;
+ GstRTPDecSession *session;
+
+ /* first get the session number */
+ if (name == NULL || sscanf (name, "rtcp_src_%d", &sessid) != 1)
+ goto no_name;
+
+ /* get or create session */
+ session = find_session_by_id (rtpdec, sessid);
+ if (!session)
+ goto no_session;
+
+ /* check if pad was requested */
+ if (session->rtcp_src != NULL)
+ goto existed;
+
+ session->rtcp_src = gst_pad_new_from_template (templ, name);
+ gst_pad_set_active (session->rtcp_src, TRUE);
+ gst_element_add_pad (GST_ELEMENT_CAST (rtpdec), session->rtcp_src);
+
+ return session->rtcp_src;
+
+ /* ERRORS */
+no_name:
+ {
+ g_warning ("rtpdec: invalid name given");
+ return NULL;
+ }
+no_session:
+ {
+ g_warning ("rtpdec: session with id %d does not exist", sessid);
+ return NULL;
+ }
+existed:
+ {
+ g_warning ("rtpdec: rtcp_src pad already requested for session %d", sessid);
+ return NULL;
+ }
+}
+
+/*
+ */
+static GstPad *
+gst_rtp_dec_request_new_pad (GstElement * element,
+ GstPadTemplate * templ, const gchar * name)
+{
+ GstRTPDec *rtpdec;
+ GstElementClass *klass;
+ GstPad *result;
+
+ g_return_val_if_fail (templ != NULL, NULL);
+ g_return_val_if_fail (GST_IS_RTP_DEC (element), NULL);
+
+ rtpdec = GST_RTP_DEC (element);
+ klass = GST_ELEMENT_GET_CLASS (element);
+
+ /* figure out the template */
+ if (templ == gst_element_class_get_pad_template (klass, "recv_rtp_sink_%d")) {
+ result = create_recv_rtp (rtpdec, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass,
+ "recv_rtcp_sink_%d")) {
+ result = create_recv_rtcp (rtpdec, templ, name);
+ } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
+ result = create_rtcp (rtpdec, templ, name);
+ } else
+ goto wrong_template;
+
+ return result;
+
+ /* ERRORS */
+wrong_template:
+ {
+ g_warning ("rtpdec: this is not our template");
+ return NULL;
+ }
+}
+
+static void
+gst_rtp_dec_release_pad (GstElement * element, GstPad * pad)
+{
+}