gst/realmedia/: Add simple rdt manager.
authorWim Taymans <wim.taymans@gmail.com>
Fri, 3 Aug 2007 16:09:01 +0000 (16:09 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Fri, 3 Aug 2007 16:09:01 +0000 (16:09 +0000)
Original commit message from CVS:
* gst/realmedia/Makefile.am:
* gst/realmedia/rdtmanager.c: (find_session_by_id),
(create_session), (free_session), (gst_rdt_manager_base_init),
(gst_rdt_manager_marshal_BOXED__UINT_UINT),
(gst_rdt_manager_class_init), (gst_rdt_manager_init),
(gst_rdt_manager_finalize), (gst_rdt_manager_query_src),
(gst_rdt_manager_chain_rtp), (gst_rdt_manager_chain_rtcp),
(gst_rdt_manager_set_property), (gst_rdt_manager_get_property),
(gst_rdt_manager_provide_clock), (gst_rdt_manager_change_state),
(create_recv_rtp), (create_recv_rtcp), (create_rtcp),
(gst_rdt_manager_request_new_pad), (gst_rdt_manager_release_pad),
(gst_rdt_manager_plugin_init):
* gst/realmedia/rdtmanager.h:
* gst/realmedia/rmdemux.c: (plugin_init):
Add simple rdt manager.

ChangeLog
gst/realmedia/Makefile.am
gst/realmedia/rdtmanager.c [new file with mode: 0644]
gst/realmedia/rdtmanager.h [new file with mode: 0644]
gst/realmedia/rmdemux.c

index 9f4784a..72597fe 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,23 @@
 2007-08-03  Wim Taymans  <wim.taymans@gmail.com>
 
+       * gst/realmedia/Makefile.am:
+       * gst/realmedia/rdtmanager.c: (find_session_by_id),
+       (create_session), (free_session), (gst_rdt_manager_base_init),
+       (gst_rdt_manager_marshal_BOXED__UINT_UINT),
+       (gst_rdt_manager_class_init), (gst_rdt_manager_init),
+       (gst_rdt_manager_finalize), (gst_rdt_manager_query_src),
+       (gst_rdt_manager_chain_rtp), (gst_rdt_manager_chain_rtcp),
+       (gst_rdt_manager_set_property), (gst_rdt_manager_get_property),
+       (gst_rdt_manager_provide_clock), (gst_rdt_manager_change_state),
+       (create_recv_rtp), (create_recv_rtcp), (create_rtcp),
+       (gst_rdt_manager_request_new_pad), (gst_rdt_manager_release_pad),
+       (gst_rdt_manager_plugin_init):
+       * gst/realmedia/rdtmanager.h:
+       * gst/realmedia/rmdemux.c: (plugin_init):
+       Add simple rdt manager.
+
+2007-08-03  Wim Taymans  <wim.taymans@gmail.com>
+
        * gst/realmedia/rdtdepay.c:
        Fix the encoding-name so that it matches what the rtsp extension sets.
 
index cf7be04..064b046 100644 (file)
@@ -1,7 +1,7 @@
 plugin_LTLIBRARIES = libgstrmdemux.la
 
 libgstrmdemux_la_SOURCES = rademux.c rmdemux.c  \
-                          rmutils.c rdtdepay.c \
+                          rmutils.c rdtdepay.c rdtmanager.c \
                           rtspreal.c realhash.c asmrules.c
 
 libgstrmdemux_la_CFLAGS = $(GST_CFLAGS) $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS)
@@ -9,7 +9,7 @@ libgstrmdemux_la_LIBADD = $(GST_PLUGINS_BASE_LIBS) $(GST_BASE_LIBS) $(GST_LIBS)\
             -lgstrtsp-@GST_MAJORMINOR@ -lgstsdp-@GST_MAJORMINOR@
 libgstrmdemux_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
 
-noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rtspreal.h realhash.h asmrules.h
+noinst_HEADERS = rademux.h rmdemux.h rmutils.h rdtdepay.h rdtmanager.h rtspreal.h realhash.h asmrules.h
 
 noinst_PROGRAMS = asmrules
 asmrules_CFLAGS = $(GST_CFLAGS) -DTEST
diff --git a/gst/realmedia/rdtmanager.c b/gst/realmedia/rdtmanager.c
new file mode 100644 (file)
index 0000000..e14c333
--- /dev/null
@@ -0,0 +1,863 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+/* Element-Checklist-Version: 5 */
+
+/**
+ * SECTION:element-rdtmanager
+ *
+ * <refsect2>
+ * <para>
+ * A simple RTP session manager used internally by rtspsrc.
+ * </para>
+ * </refsect2>
+ *
+ * Last reviewed on 2006-06-20 (0.10.4)
+ */
+
+/* #define HAVE_RTCP */
+
+#include "rdtmanager.h"
+
+GST_DEBUG_CATEGORY_STATIC (rdtmanager_debug);
+#define GST_CAT_DEFAULT (rdtmanager_debug)
+
+/* elementfactory information */
+static const GstElementDetails rdtmanager_details =
+GST_ELEMENT_DETAILS ("RTP Decoder",
+    "Codec/Parser/Network",
+    "Accepts raw RTP and RTCP packets and sends them forward",
+    "Wim Taymans <wim@fluendo.com>");
+
+/* GstRDTManager signals and args */
+enum
+{
+  SIGNAL_REQUEST_PT_MAP,
+  SIGNAL_CLEAR_PT_MAP,
+  LAST_SIGNAL
+};
+
+#define DEFAULT_LATENCY_MS      200
+
+enum
+{
+  PROP_0,
+  PROP_LATENCY
+};
+
+static GstStaticPadTemplate gst_rdt_manager_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_rdt_manager_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_rdt_manager_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_rdt_manager_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_rdt_manager_finalize (GObject * object);
+static void gst_rdt_manager_set_property (GObject * object,
+    guint prop_id, const GValue * value, GParamSpec * pspec);
+static void gst_rdt_manager_get_property (GObject * object,
+    guint prop_id, GValue * value, GParamSpec * pspec);
+
+static GstClock *gst_rdt_manager_provide_clock (GstElement * element);
+static GstStateChangeReturn gst_rdt_manager_change_state (GstElement * element,
+    GstStateChange transition);
+static GstPad *gst_rdt_manager_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name);
+static void gst_rdt_manager_release_pad (GstElement * element, GstPad * pad);
+
+static GstFlowReturn gst_rdt_manager_chain_rtp (GstPad * pad,
+    GstBuffer * buffer);
+static GstFlowReturn gst_rdt_manager_chain_rtcp (GstPad * pad,
+    GstBuffer * buffer);
+
+
+/* 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 _GstRDTManagerSession
+{
+  /* session id */
+  gint id;
+  /* the parent bin */
+  GstRDTManager *dec;
+
+  gboolean active;
+  /* we only support one ssrc and one pt */
+  guint32 ssrc;
+  guint8 pt;
+  GstCaps *caps;
+
+  /* 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 GstRDTManagerSession *
+find_session_by_id (GstRDTManager * rdtmanager, gint id)
+{
+  GSList *walk;
+
+  for (walk = rdtmanager->sessions; walk; walk = g_slist_next (walk)) {
+    GstRDTManagerSession *sess = (GstRDTManagerSession *) walk->data;
+
+    if (sess->id == id)
+      return sess;
+  }
+  return NULL;
+}
+
+/* create a session with the given id */
+static GstRDTManagerSession *
+create_session (GstRDTManager * rdtmanager, gint id)
+{
+  GstRDTManagerSession *sess;
+
+  sess = g_new0 (GstRDTManagerSession, 1);
+  sess->id = id;
+  sess->dec = rdtmanager;
+  rdtmanager->sessions = g_slist_prepend (rdtmanager->sessions, sess);
+
+  return sess;
+}
+
+static void
+free_session (GstRDTManagerSession * session)
+{
+  g_free (session);
+}
+
+static guint gst_rdt_manager_signals[LAST_SIGNAL] = { 0 };
+
+GST_BOILERPLATE (GstRDTManager, gst_rdt_manager, GstElement, GST_TYPE_ELEMENT);
+
+static void
+gst_rdt_manager_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_rdt_manager_recv_rtp_sink_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_rdt_manager_recv_rtcp_sink_template));
+  /* src pads */
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_rdt_manager_recv_rtp_src_template));
+  gst_element_class_add_pad_template (element_class,
+      gst_static_pad_template_get (&gst_rdt_manager_rtcp_src_template));
+
+  gst_element_class_set_details (element_class, &rdtmanager_details);
+}
+
+/* BOXED:UINT,UINT */
+#define g_marshal_value_peek_uint(v)     g_value_get_uint (v)
+
+void
+gst_rdt_manager_marshal_BOXED__UINT_UINT (GClosure * closure,
+    GValue * return_value,
+    guint n_param_values,
+    const GValue * param_values,
+    gpointer invocation_hint, gpointer marshal_data)
+{
+  typedef gpointer (*GMarshalFunc_BOXED__UINT_UINT) (gpointer data1,
+      guint arg_1, guint arg_2, gpointer data2);
+  register GMarshalFunc_BOXED__UINT_UINT callback;
+  register GCClosure *cc = (GCClosure *) closure;
+  register gpointer data1, data2;
+  gpointer v_return;
+
+  g_return_if_fail (return_value != NULL);
+  g_return_if_fail (n_param_values == 3);
+
+  if (G_CCLOSURE_SWAP_DATA (closure)) {
+    data1 = closure->data;
+    data2 = g_value_peek_pointer (param_values + 0);
+  } else {
+    data1 = g_value_peek_pointer (param_values + 0);
+    data2 = closure->data;
+  }
+  callback =
+      (GMarshalFunc_BOXED__UINT_UINT) (marshal_data ? marshal_data : cc->
+      callback);
+
+  v_return = callback (data1,
+      g_marshal_value_peek_uint (param_values + 1),
+      g_marshal_value_peek_uint (param_values + 2), data2);
+
+  g_value_take_boxed (return_value, v_return);
+}
+
+static void
+gst_rdt_manager_class_init (GstRDTManagerClass * g_class)
+{
+  GObjectClass *gobject_class;
+  GstElementClass *gstelement_class;
+  GstRDTManagerClass *klass;
+
+  klass = (GstRDTManagerClass *) g_class;
+  gobject_class = (GObjectClass *) klass;
+  gstelement_class = (GstElementClass *) klass;
+
+  gobject_class->finalize = gst_rdt_manager_finalize;
+  gobject_class->set_property = gst_rdt_manager_set_property;
+  gobject_class->get_property = gst_rdt_manager_get_property;
+
+  g_object_class_install_property (gobject_class, PROP_LATENCY,
+      g_param_spec_uint ("latency", "Buffer latency in ms",
+          "Amount of ms to buffer", 0, G_MAXUINT, DEFAULT_LATENCY_MS,
+          G_PARAM_READWRITE));
+
+  /**
+   * GstRDTManager::request-pt-map:
+   * @rdtmanager: the object which received the signal
+   * @session: the session
+   * @pt: the pt
+   *
+   * Request the payload type as #GstCaps for @pt in @session.
+   */
+  gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP] =
+      g_signal_new ("request-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, request_pt_map),
+      NULL, NULL, gst_rdt_manager_marshal_BOXED__UINT_UINT, GST_TYPE_CAPS, 2,
+      G_TYPE_UINT, G_TYPE_UINT);
+
+  gst_rdt_manager_signals[SIGNAL_CLEAR_PT_MAP] =
+      g_signal_new ("clear-pt-map", G_TYPE_FROM_CLASS (klass),
+      G_SIGNAL_RUN_LAST, G_STRUCT_OFFSET (GstRDTManagerClass, clear_pt_map),
+      NULL, NULL, g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, G_TYPE_NONE);
+
+  gstelement_class->provide_clock =
+      GST_DEBUG_FUNCPTR (gst_rdt_manager_provide_clock);
+  gstelement_class->change_state =
+      GST_DEBUG_FUNCPTR (gst_rdt_manager_change_state);
+  gstelement_class->request_new_pad =
+      GST_DEBUG_FUNCPTR (gst_rdt_manager_request_new_pad);
+  gstelement_class->release_pad =
+      GST_DEBUG_FUNCPTR (gst_rdt_manager_release_pad);
+
+  GST_DEBUG_CATEGORY_INIT (rdtmanager_debug, "rdtmanager", 0, "RTP decoder");
+}
+
+static void
+gst_rdt_manager_init (GstRDTManager * rdtmanager, GstRDTManagerClass * klass)
+{
+  rdtmanager->provided_clock = gst_system_clock_obtain ();
+  rdtmanager->latency = DEFAULT_LATENCY_MS;
+}
+
+static void
+gst_rdt_manager_finalize (GObject * object)
+{
+  GstRDTManager *rdtmanager;
+
+  rdtmanager = GST_RDT_MANAGER (object);
+
+  g_slist_foreach (rdtmanager->sessions, (GFunc) free_session, NULL);
+  g_slist_free (rdtmanager->sessions);
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static gboolean
+gst_rdt_manager_query_src (GstPad * pad, GstQuery * query)
+{
+  GstRDTManager *rdtmanager;
+  gboolean res;
+
+  rdtmanager = GST_RDT_MANAGER (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_rdt_manager_chain_rtp (GstPad * pad, GstBuffer * buffer)
+{
+  GstFlowReturn res;
+  GstRDTManager *rdtmanager;
+  GstRDTManagerSession *session;
+  guint32 ssrc;
+  guint8 pt;
+
+  rdtmanager = GST_RDT_MANAGER (GST_PAD_PARENT (pad));
+
+  GST_DEBUG_OBJECT (rdtmanager, "got rtp packet");
+
+  ssrc = 0;
+  pt = 0;
+
+  GST_DEBUG_OBJECT (rdtmanager, "SSRC %08x, 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;
+    GstCaps *caps;
+    GValue ret = { 0 };
+    GValue args[3] = { {0}
+    , {0}
+    , {0}
+    };
+
+    GST_DEBUG_OBJECT (rdtmanager, "creating stream");
+
+    session->ssrc = ssrc;
+    session->pt = pt;
+
+    /* get pt map */
+    g_value_init (&args[0], GST_TYPE_ELEMENT);
+    g_value_set_object (&args[0], rdtmanager);
+    g_value_init (&args[1], G_TYPE_UINT);
+    g_value_set_uint (&args[1], session->id);
+    g_value_init (&args[2], G_TYPE_UINT);
+    g_value_set_uint (&args[2], pt);
+
+    g_value_init (&ret, GST_TYPE_CAPS);
+    g_value_set_boxed (&ret, NULL);
+
+    g_signal_emitv (args, gst_rdt_manager_signals[SIGNAL_REQUEST_PT_MAP], 0,
+        &ret);
+
+    caps = (GstCaps *) g_value_get_boxed (&ret);
+
+    name = g_strdup_printf ("recv_rtp_src_%d_%u_%d", session->id, ssrc, pt);
+    klass = GST_ELEMENT_GET_CLASS (rdtmanager);
+    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_caps (session->recv_rtp_src, caps);
+
+    gst_pad_set_element_private (session->recv_rtp_src, session);
+    gst_pad_set_query_function (session->recv_rtp_src,
+        gst_rdt_manager_query_src);
+    gst_pad_set_active (session->recv_rtp_src, TRUE);
+    gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_src);
+
+    session->active = TRUE;
+  }
+
+  gst_buffer_set_caps (buffer, GST_PAD_CAPS (session->recv_rtp_src));
+
+  res = gst_pad_push (session->recv_rtp_src, buffer);
+
+  return res;
+}
+
+static GstFlowReturn
+gst_rdt_manager_chain_rtcp (GstPad * pad, GstBuffer * buffer)
+{
+  GstRDTManager *src;
+
+#ifdef HAVE_RTCP
+  gboolean valid;
+  GstRTCPPacket packet;
+  gboolean more;
+#endif
+
+  src = GST_RDT_MANAGER (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_rdt_manager_set_property (GObject * object, guint prop_id,
+    const GValue * value, GParamSpec * pspec)
+{
+  GstRDTManager *src;
+
+  src = GST_RDT_MANAGER (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      src->latency = g_value_get_uint (value);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static void
+gst_rdt_manager_get_property (GObject * object, guint prop_id, GValue * value,
+    GParamSpec * pspec)
+{
+  GstRDTManager *src;
+
+  src = GST_RDT_MANAGER (object);
+
+  switch (prop_id) {
+    case PROP_LATENCY:
+      g_value_set_uint (value, src->latency);
+      break;
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+      break;
+  }
+}
+
+static GstClock *
+gst_rdt_manager_provide_clock (GstElement * element)
+{
+  GstRDTManager *rdtmanager;
+
+  rdtmanager = GST_RDT_MANAGER (element);
+
+  return GST_CLOCK_CAST (gst_object_ref (rdtmanager->provided_clock));
+}
+
+static GstStateChangeReturn
+gst_rdt_manager_change_state (GstElement * element, GstStateChange transition)
+{
+  GstStateChangeReturn ret;
+  GstRDTManager *rdtmanager;
+
+  rdtmanager = GST_RDT_MANAGER (element);
+
+  switch (transition) {
+    default:
+      break;
+  }
+
+  ret = GST_ELEMENT_CLASS (parent_class)->change_state (element, transition);
+
+  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:
+      break;
+  }
+
+  return ret;
+}
+
+/* Create a pad for receiving RTP for the session in @name
+ */
+static GstPad *
+create_recv_rtp (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstRDTManagerSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rdtmanager, "finding session %d", sessid);
+
+  /* get or create session */
+  session = find_session_by_id (rdtmanager, sessid);
+  if (!session) {
+    GST_DEBUG_OBJECT (rdtmanager, "creating session %d", sessid);
+    /* create session now */
+    session = create_session (rdtmanager, sessid);
+    if (session == NULL)
+      goto create_error;
+  }
+  /* check if pad was requested */
+  if (session->recv_rtp_sink != NULL)
+    goto existed;
+
+  GST_DEBUG_OBJECT (rdtmanager, "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_rdt_manager_chain_rtp);
+  gst_pad_set_active (session->recv_rtp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtp_sink);
+
+  return session->recv_rtp_sink;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rdtmanager: invalid name given");
+    return NULL;
+  }
+create_error:
+  {
+    /* create_session already warned */
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rdtmanager: 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 (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstRDTManagerSession *session;
+
+  /* first get the session number */
+  if (name == NULL || sscanf (name, "recv_rtcp_sink_%d", &sessid) != 1)
+    goto no_name;
+
+  GST_DEBUG_OBJECT (rdtmanager, "finding session %d", sessid);
+
+  /* get the session, it must exist or we error */
+  session = find_session_by_id (rdtmanager, sessid);
+  if (!session)
+    goto no_session;
+
+  /* check if pad was requested */
+  if (session->recv_rtcp_sink != NULL)
+    goto existed;
+
+  GST_DEBUG_OBJECT (rdtmanager, "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_rdt_manager_chain_rtcp);
+  gst_pad_set_active (session->recv_rtcp_sink, TRUE);
+  gst_element_add_pad (GST_ELEMENT_CAST (rdtmanager), session->recv_rtcp_sink);
+
+  return session->recv_rtcp_sink;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rdtmanager: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rdtmanager: no session with id %d", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rdtmanager: 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 (GstRDTManager * rdtmanager, GstPadTemplate * templ,
+    const gchar * name)
+{
+  guint sessid;
+  GstRDTManagerSession *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 (rdtmanager, 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 (rdtmanager), session->rtcp_src);
+
+  return session->rtcp_src;
+
+  /* ERRORS */
+no_name:
+  {
+    g_warning ("rdtmanager: invalid name given");
+    return NULL;
+  }
+no_session:
+  {
+    g_warning ("rdtmanager: session with id %d does not exist", sessid);
+    return NULL;
+  }
+existed:
+  {
+    g_warning ("rdtmanager: rtcp_src pad already requested for session %d",
+        sessid);
+    return NULL;
+  }
+}
+
+/* 
+ */
+static GstPad *
+gst_rdt_manager_request_new_pad (GstElement * element,
+    GstPadTemplate * templ, const gchar * name)
+{
+  GstRDTManager *rdtmanager;
+  GstElementClass *klass;
+  GstPad *result;
+
+  g_return_val_if_fail (templ != NULL, NULL);
+  g_return_val_if_fail (GST_IS_RDT_MANAGER (element), NULL);
+
+  rdtmanager = GST_RDT_MANAGER (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 (rdtmanager, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass,
+          "recv_rtcp_sink_%d")) {
+    result = create_recv_rtcp (rdtmanager, templ, name);
+  } else if (templ == gst_element_class_get_pad_template (klass, "rtcp_src_%d")) {
+    result = create_rtcp (rdtmanager, templ, name);
+  } else
+    goto wrong_template;
+
+  return result;
+
+  /* ERRORS */
+wrong_template:
+  {
+    g_warning ("rdtmanager: this is not our template");
+    return NULL;
+  }
+}
+
+static void
+gst_rdt_manager_release_pad (GstElement * element, GstPad * pad)
+{
+}
+
+gboolean
+gst_rdt_manager_plugin_init (GstPlugin * plugin)
+{
+  return gst_element_register (plugin, "rdtmanager",
+      GST_RANK_MARGINAL, GST_TYPE_RDT_MANAGER);
+}
diff --git a/gst/realmedia/rdtmanager.h b/gst/realmedia/rdtmanager.h
new file mode 100644 (file)
index 0000000..c83e2b9
--- /dev/null
@@ -0,0 +1,83 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ * Unless otherwise indicated, Source Code is licensed under MIT license.
+ * See further explanation attached in License Statement (distributed in the file
+ * LICENSE).
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy of
+ * this software and associated documentation files (the "Software"), to deal in
+ * the Software without restriction, including without limitation the rights to
+ * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
+ * of the Software, and to permit persons to whom the Software is furnished to do
+ * so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in all
+ * copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef __GST_RDT_MANAGER_H__
+#define __GST_RDT_MANAGER_H__
+
+#include <gst/gst.h>
+
+G_BEGIN_DECLS
+
+#define GST_TYPE_RDT_MANAGER           (gst_rdt_manager_get_type())
+#define GST_IS_RDT_MANAGER(obj)        (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RDT_MANAGER))
+#define GST_IS_RDT_MANAGER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RDT_MANAGER))
+#define GST_RDT_MANAGER(obj)           (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RDT_MANAGER, GstRDTManager))
+#define GST_RDT_MANAGER_CLASS(klass)   (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RDT_MANAGER, GstRDTManagerClass))
+
+typedef struct _GstRDTManager GstRDTManager;
+typedef struct _GstRDTManagerClass GstRDTManagerClass;
+typedef struct _GstRDTManagerSession GstRDTManagerSession;
+
+struct _GstRDTManager {
+  GstElement  element;
+
+  guint       latency;
+  GSList     *sessions;
+  GstClock   *provided_clock;
+};
+
+struct _GstRDTManagerClass {
+  GstElementClass parent_class;
+
+  /* get the caps for pt */
+  GstCaps* (*request_pt_map)  (GstRDTManager *rtpdec, guint session, guint pt);
+
+  void     (*clear_pt_map)    (GstRDTManager *rtpdec);
+};
+
+GType gst_rdt_manager_get_type(void);
+
+gboolean gst_rdt_manager_plugin_init (GstPlugin * plugin);
+
+G_END_DECLS
+
+#endif /* __GST_RDT_MANAGER_H__ */
index 0045d87..5575b61 100644 (file)
@@ -29,6 +29,7 @@
 
 #include "rmdemux.h"
 #include "rdtdepay.h"
+#include "rdtmanager.h"
 #include "rtspreal.h"
 #include "rmutils.h"
 #include "rademux.h"
@@ -2083,6 +2084,9 @@ plugin_init (GstPlugin * plugin)
   if (!gst_rdt_depay_plugin_init (plugin))
     return FALSE;
 
+  if (!gst_rdt_manager_plugin_init (plugin))
+    return FALSE;
+
   if (!gst_rtsp_real_plugin_init (plugin))
     return FALSE;