? rtsp.diff
Index: Makefile.am
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/Makefile.am,v
retrieving revision 1.6
diff -u -3 -p -b -B -d -r1.6 Makefile.am
--- Makefile.am	10 Jul 2006 16:41:57 -0000	1.6
+++ Makefile.am	22 Jul 2006 21:41:28 -0000
@@ -1,7 +1,6 @@
 plugin_LTLIBRARIES = libgstrtsp.la
 
 libgstrtsp_la_SOURCES = gstrtsp.c gstrtspsrc.c \
-			gstrtpdec.c		\
 			rtspconnection.c	\
 			rtspdefs.c		\
 			rtspmessage.c		\
@@ -19,4 +18,4 @@ test_SOURCES = test.c rtspdefs.c rtspurl
 test_CFLAGS = $(GST_CFLAGS)
 test_LDFLAGS = $(GST_LIBS) $(WIN32_LIBS)
 
-noinst_HEADERS = gstrtspsrc.h gstrtsp.h gstrtpdec.h rtsptransport.h rtsp.h rtspurl.h rtspconnection.h rtspdefs.h rtspmessage.h sdp.h sdpmessage.h
+noinst_HEADERS = gstrtspsrc.h gstrtsp.h rtsptransport.h rtsp.h rtspurl.h rtspconnection.h rtspdefs.h rtspmessage.h sdp.h sdpmessage.h
Index: gstrtsp.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/gstrtsp.c,v
retrieving revision 1.4
diff -u -3 -p -b -B -d -r1.4 gstrtsp.c
--- gstrtsp.c	9 Feb 2006 14:20:14 -0000	1.4
+++ gstrtsp.c	22 Jul 2006 21:41:28 -0000
@@ -21,7 +21,6 @@
 #include "config.h"
 #endif
 
-#include "gstrtpdec.h"
 #include "gstrtspsrc.h"
 
 static gboolean
@@ -30,8 +29,6 @@ plugin_init (GstPlugin * plugin)
   if (!gst_element_register (plugin, "rtspsrc", GST_RANK_NONE,
           GST_TYPE_RTSPSRC))
     return FALSE;
-  if (!gst_element_register (plugin, "rtpdec", GST_RANK_NONE, GST_TYPE_RTPDEC))
-    return FALSE;
 
   return TRUE;
 }
Index: gstrtspsrc.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/gstrtspsrc.c,v
retrieving revision 1.29
diff -u -3 -p -b -B -d -r1.29 gstrtspsrc.c
--- gstrtspsrc.c	15 Jul 2006 15:25:05 -0000	1.29
+++ gstrtspsrc.c	22 Jul 2006 21:41:29 -0000
@@ -86,12 +86,6 @@ GST_STATIC_PAD_TEMPLATE ("rtp_stream%d",
     GST_PAD_SOMETIMES,
     GST_STATIC_CAPS_ANY);
 
-static GstStaticPadTemplate rtcptemplate =
-GST_STATIC_PAD_TEMPLATE ("rtcp_stream%d",
-    GST_PAD_SRC,
-    GST_PAD_SOMETIMES,
-    GST_STATIC_CAPS_ANY);
-
 enum
 {
   /* FILL ME */
@@ -133,11 +127,11 @@ gst_rtsp_proto_get_type (void)
 
 
 static void gst_rtspsrc_base_init (gpointer g_class);
-static void gst_rtspsrc_class_init (GstRTSPSrc * klass);
-static void gst_rtspsrc_init (GstRTSPSrc * rtspsrc);
 
 static void gst_rtspsrc_uri_handler_init (gpointer g_iface,
     gpointer iface_data);
+static gboolean gst_rtspsrc_uri_set_uri (GstURIHandler * handler,
+    const gchar * uri);
 
 static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element,
     GstStateChange transition);
@@ -147,30 +141,13 @@ static void gst_rtspsrc_set_property (GO
 static void gst_rtspsrc_get_property (GObject * object, guint prop_id,
     GValue * value, GParamSpec * pspec);
 
-static void gst_rtspsrc_loop (GstRTSPSrc * src);
-
-static GstElementClass *parent_class = NULL;
+static void gst_rtspsrc_loop (gpointer data);
 
 /*static guint gst_rtspsrc_signals[LAST_SIGNAL] = { 0 }; */
 
-GType
-gst_rtspsrc_get_type (void)
+static void
+_do_init (GType rtspsrc_type)
 {
-  static GType rtspsrc_type = 0;
-
-  if (!rtspsrc_type) {
-    static const GTypeInfo rtspsrc_info = {
-      sizeof (GstRTSPSrcClass),
-      gst_rtspsrc_base_init,
-      NULL,
-      (GClassInitFunc) gst_rtspsrc_class_init,
-      NULL,
-      NULL,
-      sizeof (GstRTSPSrc),
-      0,
-      (GInstanceInitFunc) gst_rtspsrc_init,
-      NULL
-    };
     static const GInterfaceInfo urihandler_info = {
       gst_rtspsrc_uri_handler_init,
       NULL,
@@ -179,16 +156,13 @@ gst_rtspsrc_get_type (void)
 
     GST_DEBUG_CATEGORY_INIT (rtspsrc_debug, "rtspsrc", 0, "RTSP src");
 
-    rtspsrc_type =
-        g_type_register_static (GST_TYPE_ELEMENT, "GstRTSPSrc", &rtspsrc_info,
-        0);
-
     g_type_add_interface_static (rtspsrc_type, GST_TYPE_URI_HANDLER,
         &urihandler_info);
-  }
-  return rtspsrc_type;
 }
 
+GST_BOILERPLATE_FULL (GstRTSPSrc, gst_rtspsrc, GstBin, GST_TYPE_BIN,
+    _do_init);
+
 static void
 gst_rtspsrc_base_init (gpointer g_class)
 {
@@ -196,14 +170,38 @@ gst_rtspsrc_base_init (gpointer g_class)
 
   gst_element_class_add_pad_template (element_class,
       gst_static_pad_template_get (&rtptemplate));
-  gst_element_class_add_pad_template (element_class,
-      gst_static_pad_template_get (&rtcptemplate));
 
   gst_element_class_set_details (element_class, &gst_rtspsrc_details);
 }
 
 static void
-gst_rtspsrc_class_init (GstRTSPSrc * klass)
+foreach_free (gpointer key, gpointer data, gpointer user_data)
+{
+  g_free (data);
+}
+
+static void
+gst_rtspsrc_finalize (GObject * object)
+{
+  GstRTSPSrc *src = GST_RTSPSRC (object);
+
+  if (src->task_lock) {
+    g_static_rec_mutex_free (src->task_lock);
+    g_free (src->task_lock);
+    src->task_lock = NULL;
+  }
+
+  if (src->streams) {
+    g_hash_table_foreach (src->streams, foreach_free, NULL);
+    g_hash_table_destroy (src->streams);
+    src->streams = NULL;
+  }
+
+  G_OBJECT_CLASS (parent_class)->finalize (object);
+}
+
+static void
+gst_rtspsrc_class_init (GstRTSPSrcClass * klass)
 {
   GObjectClass *gobject_class;
   GstElementClass *gstelement_class;
@@ -215,6 +213,7 @@ gst_rtspsrc_class_init (GstRTSPSrc * kla
 
   gobject_class->set_property = gst_rtspsrc_set_property;
   gobject_class->get_property = gst_rtspsrc_get_property;
+  gobject_class->finalize = gst_rtspsrc_finalize;
 
   g_object_class_install_property (gobject_class, PROP_LOCATION,
       g_param_spec_string ("location", "RTSP Location",
@@ -241,8 +240,12 @@ gst_rtspsrc_class_init (GstRTSPSrc * kla
 }
 
 static void
-gst_rtspsrc_init (GstRTSPSrc * src)
+gst_rtspsrc_init (GstRTSPSrc * src, GstRTSPSrcClass * g_class)
 {
+  src->task_lock = g_new (GStaticRecMutex, 1);
+  g_static_rec_mutex_init (src->task_lock);
+
+  src->streams = g_hash_table_new (g_direct_hash, g_direct_equal);
 }
 
 static void
@@ -255,8 +258,8 @@ gst_rtspsrc_set_property (GObject * obje
 
   switch (prop_id) {
     case PROP_LOCATION:
-      g_free (rtspsrc->location);
-      rtspsrc->location = g_value_dup_string (value);
+      gst_rtspsrc_uri_set_uri (GST_URI_HANDLER (rtspsrc),
+          g_value_get_string (value));
       break;
     case PROP_PROTOCOLS:
       rtspsrc->protocols = g_value_get_flags (value);
@@ -300,70 +303,6 @@ gst_rtspsrc_get_property (GObject * obje
   }
 }
 
-static GstRTSPStream *
-gst_rtspsrc_create_stream (GstRTSPSrc * src)
-{
-  GstRTSPStream *s;
-
-  s = g_new0 (GstRTSPStream, 1);
-  s->parent = src;
-  s->id = src->numstreams++;
-
-  src->streams = g_list_append (src->streams, s);
-
-  return s;
-}
-
-static gboolean
-gst_rtspsrc_add_element (GstRTSPSrc * src, GstElement * element)
-{
-  gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (src));
-
-  return TRUE;
-}
-
-static GstStateChangeReturn
-gst_rtspsrc_set_state (GstRTSPSrc * src, GstState state)
-{
-  GstStateChangeReturn ret;
-  GList *streams;
-
-  ret = GST_STATE_CHANGE_SUCCESS;
-
-  /* for all streams */
-  for (streams = src->streams; streams; streams = g_list_next (streams)) {
-    GstRTSPStream *stream;
-
-    stream = (GstRTSPStream *) streams->data;
-
-    /* first our rtp session manager */
-    if (stream->rtpdec) {
-      if ((ret =
-              gst_element_set_state (stream->rtpdec,
-                  state)) == GST_STATE_CHANGE_FAILURE)
-        goto done;
-    }
-
-    /* then our sources */
-    if (stream->rtpsrc) {
-      if ((ret =
-              gst_element_set_state (stream->rtpsrc,
-                  state)) == GST_STATE_CHANGE_FAILURE)
-        goto done;
-    }
-
-    if (stream->rtcpsrc) {
-      if ((ret =
-              gst_element_set_state (stream->rtcpsrc,
-                  state)) == GST_STATE_CHANGE_FAILURE)
-        goto done;
-    }
-  }
-
-done:
-  return ret;
-}
-
 #define PARSE_INT(p, del, res)          \
 G_STMT_START {                          \
   gchar *t = p;                         \
@@ -411,8 +350,10 @@ gst_rtspsrc_parse_rtpmap (gchar * rtpmap
     return FALSE;
 
   PARSE_STRING (p, "/", *name);
-  if (*name == NULL)
-    return FALSE;
+  if (*name == NULL) {
+    *name = p;
+    return TRUE;
+  }
 
   t = p;
   p = strstr (p, "/");
@@ -534,18 +475,15 @@ gst_rtspsrc_media_to_caps (SDPMedia * me
 }
 
 static gboolean
-gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream, SDPMedia * media,
-    gint * rtpport, gint * rtcpport)
+gst_rtspsrc_stream_setup_rtp (GstRTSPSrc * src, GstRTSPStream * stream,
+    SDPMedia * media, gint * rtpport, gint * rtcpport)
 {
   GstStateChangeReturn ret;
-  GstRTSPSrc *src;
   GstCaps *caps;
   GstElement *tmp, *rtp, *rtcp;
   gint tmp_rtp, tmp_rtcp;
   guint count;
 
-  src = stream->parent;
-
   tmp = NULL;
   rtp = NULL;
   rtcp = NULL;
@@ -615,15 +553,15 @@ again:
     goto port_error;
 
   /* we manage these elements */
+  gst_bin_add (GST_BIN (src), rtp);
   stream->rtpsrc = rtp;
-  gst_rtspsrc_add_element (src, stream->rtpsrc);
+  gst_bin_add (GST_BIN (src), rtcp);
   stream->rtcpsrc = rtcp;
-  gst_rtspsrc_add_element (src, stream->rtcpsrc);
-
-  caps = gst_rtspsrc_media_to_caps (media);
 
   /* set caps */
+  caps = gst_rtspsrc_media_to_caps (media);
   g_object_set (G_OBJECT (stream->rtpsrc), "caps", caps, NULL);
+  gst_caps_unref (caps);
 
   return TRUE;
 
@@ -677,22 +615,28 @@ cleanup:
   }
 }
 
+static void
+foreach_add (gpointer data, gpointer user_data)
+{
+  GstPad *pad = gst_ghost_pad_new (NULL, GST_PAD (data));
+
+  gst_element_add_pad (GST_ELEMENT (user_data), pad);
+  GST_DEBUG_OBJECT (user_data, "Added pad %s.%s.", GST_DEBUG_PAD_NAME (pad));
+}
+
 static gboolean
-gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
-    RTSPTransport * transport)
+gst_rtspsrc_stream_configure_transport (GstRTSPSrc * src,
+    GstRTSPStream * stream, RTSPTransport * transport)
 {
-  GstRTSPSrc *src;
   GstPad *pad;
   GstStateChangeReturn ret;
-  gchar *name;
-
-  src = stream->parent;
+  GstIterator *it;
 
-  if (!(stream->rtpdec = gst_element_factory_make ("rtpdec", NULL)))
+  if (!(stream->rtpdec = gst_element_factory_make ("rtpdepay", NULL)))
     goto no_element;
 
   /* we manage this element */
-  gst_rtspsrc_add_element (src, stream->rtpdec);
+  gst_bin_add (GST_BIN (src), stream->rtpdec);
 
   if ((ret =
           gst_element_set_state (stream->rtpdec,
@@ -718,11 +662,9 @@ gst_rtspsrc_stream_configure_transport (
     gst_object_unref (pad);
   }
 
-  pad = gst_element_get_pad (stream->rtpdec, "srcrtp");
-  name = g_strdup_printf ("rtp_stream%d", stream->id);
-  gst_element_add_pad (GST_ELEMENT_CAST (src), gst_ghost_pad_new (name, pad));
-  g_free (name);
-  gst_object_unref (pad);
+  it = gst_element_iterate_src_pads (GST_ELEMENT (stream->rtpdec));
+  gst_iterator_foreach (it, foreach_add, src);
+  gst_iterator_free (it);
 
   return TRUE;
 
@@ -738,49 +680,31 @@ start_rtpdec_failure:
   }
 }
 
-static gint
-find_stream (GstRTSPStream * stream, gconstpointer a)
-{
-  gint channel = GPOINTER_TO_INT (a);
-
-  if (stream->rtpchannel == channel || stream->rtcpchannel == channel)
-    return 0;
-
-  return -1;
-}
-
 static void
-gst_rtspsrc_loop (GstRTSPSrc * src)
+gst_rtspsrc_loop (gpointer user_data)
 {
   RTSPMessage response = { 0 };
   RTSPResult res;
   gint channel;
-  GList *lstream;
   GstRTSPStream *stream;
   GstPad *outpad = NULL;
   guint8 *data;
   guint size;
+  GstRTSPSrc *src = GST_RTSPSRC (user_data);
+  GstFlowReturn ret;
 
-  do {
-    GST_DEBUG ("doing reveive");
     if ((res = rtsp_connection_receive (src->connection, &response)) < 0)
       goto receive_error;
-    GST_DEBUG ("got packet");
-  }
-  while (response.type != RTSP_MESSAGE_DATA);
+  if (response.type != RTSP_MESSAGE_DATA)
+    goto no_data;
 
   channel = response.type_data.data.channel;
+  stream = g_hash_table_lookup (src->streams, GINT_TO_POINTER (channel));
 
-  lstream = g_list_find_custom (src->streams, GINT_TO_POINTER (channel),
-      (GCompareFunc) find_stream);
-  if (!lstream)
+  if (!stream)
     goto unknown_stream;
 
-  stream = (GstRTSPStream *) lstream->data;
-  if (channel == stream->rtpchannel)
     outpad = stream->rtpdecrtp;
-  else if (channel == stream->rtcpchannel)
-    outpad = stream->rtpdecrtcp;
 
   rtsp_message_get_body (&response, &data, &size);
 
@@ -796,31 +720,41 @@ gst_rtspsrc_loop (GstRTSPSrc * src)
 
   /* and chain buffer to internal element */
   {
-    GstBuffer *buf;
+    GstBuffer *buf = gst_buffer_new ();
 
-    buf = gst_buffer_new_and_alloc (size);
-    memcpy (GST_BUFFER_DATA (buf), data, size);
+    gst_buffer_set_data (buf, response.body, response.body_size);
+    buf->malloc_data = response.body;
+    response.body = NULL;
+    response.body_size = 0;
 
-    if (gst_pad_chain (outpad, buf) != GST_FLOW_OK)
-      goto need_pause;
+    if ((ret = gst_pad_chain (outpad, buf)) != GST_FLOW_OK)
+      goto chain_failed;
   }
+  return;
 
 unknown_stream:
-
+  {
+    GST_DEBUG_OBJECT (src, "Could not determine the stream for channel %d.",
+        channel);
   return;
-
+  }
+no_data:
+  {
+    GST_DEBUG_OBJECT (src, "Received a reponse of type %d.", response.type);
+    return;
+  }
 receive_error:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Could not receive message."), (NULL));
-    /*
-       gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_EOS));
-     */
-    goto need_pause;
+    gst_task_pause (src->task);
+    return;
   }
-need_pause:
+chain_failed:
   {
-    gst_task_pause (src->task);
+    GST_DEBUG_OBJECT (src, "Could not chain buffer for channel "
+        "%d on pad %s.%s: %s.", channel, GST_DEBUG_PAD_NAME (outpad),
+        gst_flow_get_name (ret));
     return;
   }
 }
@@ -866,17 +800,390 @@ receive_error:
   }
 error_response:
   {
+    switch (response->type_data.response.code) {
+      case RTSP_STS_NOT_FOUND:
+        GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND, ("%s",
+              response->type_data.response.reason), (NULL));
+        break;
+      default:
     GST_ELEMENT_ERROR (src, RESOURCE, READ, ("Got error response: %d (%s).",
             response->type_data.response.code,
             response->type_data.response.reason), (NULL));
+    }
     return FALSE;
   }
 }
 
+/*
+ * The following code has been copied from
+ * xine-lib-1.1.1/src/input/libreal/real.c.
+ */
+
+#include <stdint.h>
+
+inline static unsigned int ByteSwap32(unsigned int x)
+{
+#if __CPU__ > 386
+  __asm("bswap   %0":
+    "=r" (x)     :
+#else
+  __asm("xchgb   %b0,%h0\n"
+    " rorl    $16,%0\n"
+    " xchgb   %b0,%h0":
+    "=q" (x)          :
+#endif
+    "0" (x));
+  return x;
+}
+#define bswap_32(x) ByteSwap32(x)
+
+#define be2me_32(x) bswap_32(x)
+#define le2me_32(x) (x)
+
+#define ALE_32(x) (le2me_32(*(uint32_t*)(x)))
+#define LE_32(x) ALE_32(x)
+
+#undef MAX
+#define lprintf GST_DEBUG
+
+const unsigned char xor_table[] = {
+    0x05, 0x18, 0x74, 0xd0, 0x0d, 0x09, 0x02, 0x53,
+    0xc0, 0x01, 0x05, 0x05, 0x67, 0x03, 0x19, 0x70,
+    0x08, 0x27, 0x66, 0x10, 0x10, 0x72, 0x08, 0x09,
+    0x63, 0x11, 0x03, 0x71, 0x08, 0x08, 0x70, 0x02,
+    0x10, 0x57, 0x05, 0x18, 0x54, 0x00, 0x00, 0x00 };
+
+#define BE_32C(x,y) do { *(uint32_t *)(x) = be2me_32((y)); } while(0)
+#define LE_32C(x,y) do { *(uint32_t *)(x) = le2me_32((y)); } while(0)
+
+#define MAX(x,y) ((x>y) ? x : y)
+
+
+static void hash(char *field, char *param) {
+
+  uint32_t a, b, c, d;
+ 
+
+  /* fill variables */
+  a = LE_32(field);
+  b = LE_32(field+4);
+  c = LE_32(field+8);
+  d = LE_32(field+12);
+  
+  lprintf("hash input: %x %x %x %x\n", a, b, c, d);
+  lprintf("hash parameter:\n");
+#ifdef LOG
+  xine_hexdump(param, 64);
+#endif
+  
+  a = ((b & c) | (~b & d)) + LE_32((param+0x00)) + a - 0x28955B88;
+  a = ((a << 0x07) | (a >> 0x19)) + b;
+  d = ((a & b) | (~a & c)) + LE_32((param+0x04)) + d - 0x173848AA;
+  d = ((d << 0x0c) | (d >> 0x14)) + a;
+  c = ((d & a) | (~d & b)) + LE_32((param+0x08)) + c + 0x242070DB;
+  c = ((c << 0x11) | (c >> 0x0f)) + d;
+  b = ((c & d) | (~c & a)) + LE_32((param+0x0c)) + b - 0x3E423112;
+  b = ((b << 0x16) | (b >> 0x0a)) + c;
+  a = ((b & c) | (~b & d)) + LE_32((param+0x10)) + a - 0x0A83F051;
+  a = ((a << 0x07) | (a >> 0x19)) + b;
+  d = ((a & b) | (~a & c)) + LE_32((param+0x14)) + d + 0x4787C62A;
+  d = ((d << 0x0c) | (d >> 0x14)) + a;
+  c = ((d & a) | (~d & b)) + LE_32((param+0x18)) + c - 0x57CFB9ED;
+  c = ((c << 0x11) | (c >> 0x0f)) + d;
+  b = ((c & d) | (~c & a)) + LE_32((param+0x1c)) + b - 0x02B96AFF;
+  b = ((b << 0x16) | (b >> 0x0a)) + c;
+  a = ((b & c) | (~b & d)) + LE_32((param+0x20)) + a + 0x698098D8;
+  a = ((a << 0x07) | (a >> 0x19)) + b;
+  d = ((a & b) | (~a & c)) + LE_32((param+0x24)) + d - 0x74BB0851;
+  d = ((d << 0x0c) | (d >> 0x14)) + a;
+  c = ((d & a) | (~d & b)) + LE_32((param+0x28)) + c - 0x0000A44F;
+  c = ((c << 0x11) | (c >> 0x0f)) + d;
+  b = ((c & d) | (~c & a)) + LE_32((param+0x2C)) + b - 0x76A32842;
+  b = ((b << 0x16) | (b >> 0x0a)) + c;
+  a = ((b & c) | (~b & d)) + LE_32((param+0x30)) + a + 0x6B901122;
+  a = ((a << 0x07) | (a >> 0x19)) + b;
+  d = ((a & b) | (~a & c)) + LE_32((param+0x34)) + d - 0x02678E6D;
+  d = ((d << 0x0c) | (d >> 0x14)) + a;
+  c = ((d & a) | (~d & b)) + LE_32((param+0x38)) + c - 0x5986BC72;
+  c = ((c << 0x11) | (c >> 0x0f)) + d;
+  b = ((c & d) | (~c & a)) + LE_32((param+0x3c)) + b + 0x49B40821;
+  b = ((b << 0x16) | (b >> 0x0a)) + c;
+  
+  a = ((b & d) | (~d & c)) + LE_32((param+0x04)) + a - 0x09E1DA9E;
+  a = ((a << 0x05) | (a >> 0x1b)) + b;
+  d = ((a & c) | (~c & b)) + LE_32((param+0x18)) + d - 0x3FBF4CC0;
+  d = ((d << 0x09) | (d >> 0x17)) + a;
+  c = ((d & b) | (~b & a)) + LE_32((param+0x2c)) + c + 0x265E5A51;
+  c = ((c << 0x0e) | (c >> 0x12)) + d;
+  b = ((c & a) | (~a & d)) + LE_32((param+0x00)) + b - 0x16493856;
+  b = ((b << 0x14) | (b >> 0x0c)) + c;
+  a = ((b & d) | (~d & c)) + LE_32((param+0x14)) + a - 0x29D0EFA3;
+  a = ((a << 0x05) | (a >> 0x1b)) + b;
+  d = ((a & c) | (~c & b)) + LE_32((param+0x28)) + d + 0x02441453;
+  d = ((d << 0x09) | (d >> 0x17)) + a;
+  c = ((d & b) | (~b & a)) + LE_32((param+0x3c)) + c - 0x275E197F;
+  c = ((c << 0x0e) | (c >> 0x12)) + d;
+  b = ((c & a) | (~a & d)) + LE_32((param+0x10)) + b - 0x182C0438;
+  b = ((b << 0x14) | (b >> 0x0c)) + c;
+  a = ((b & d) | (~d & c)) + LE_32((param+0x24)) + a + 0x21E1CDE6;
+  a = ((a << 0x05) | (a >> 0x1b)) + b;
+  d = ((a & c) | (~c & b)) + LE_32((param+0x38)) + d - 0x3CC8F82A;
+  d = ((d << 0x09) | (d >> 0x17)) + a;
+  c = ((d & b) | (~b & a)) + LE_32((param+0x0c)) + c - 0x0B2AF279;
+  c = ((c << 0x0e) | (c >> 0x12)) + d;
+  b = ((c & a) | (~a & d)) + LE_32((param+0x20)) + b + 0x455A14ED;
+  b = ((b << 0x14) | (b >> 0x0c)) + c;
+  a = ((b & d) | (~d & c)) + LE_32((param+0x34)) + a - 0x561C16FB;
+  a = ((a << 0x05) | (a >> 0x1b)) + b;
+  d = ((a & c) | (~c & b)) + LE_32((param+0x08)) + d - 0x03105C08;
+  d = ((d << 0x09) | (d >> 0x17)) + a;
+  c = ((d & b) | (~b & a)) + LE_32((param+0x1c)) + c + 0x676F02D9;
+  c = ((c << 0x0e) | (c >> 0x12)) + d;
+  b = ((c & a) | (~a & d)) + LE_32((param+0x30)) + b - 0x72D5B376;
+  b = ((b << 0x14) | (b >> 0x0c)) + c;
+  
+  a = (b ^ c ^ d) + LE_32((param+0x14)) + a - 0x0005C6BE;
+  a = ((a << 0x04) | (a >> 0x1c)) + b;
+  d = (a ^ b ^ c) + LE_32((param+0x20)) + d - 0x788E097F;
+  d = ((d << 0x0b) | (d >> 0x15)) + a;
+  c = (d ^ a ^ b) + LE_32((param+0x2c)) + c + 0x6D9D6122;
+  c = ((c << 0x10) | (c >> 0x10)) + d;
+  b = (c ^ d ^ a) + LE_32((param+0x38)) + b - 0x021AC7F4;
+  b = ((b << 0x17) | (b >> 0x09)) + c;
+  a = (b ^ c ^ d) + LE_32((param+0x04)) + a - 0x5B4115BC;
+  a = ((a << 0x04) | (a >> 0x1c)) + b;
+  d = (a ^ b ^ c) + LE_32((param+0x10)) + d + 0x4BDECFA9;
+  d = ((d << 0x0b) | (d >> 0x15)) + a;
+  c = (d ^ a ^ b) + LE_32((param+0x1c)) + c - 0x0944B4A0;
+  c = ((c << 0x10) | (c >> 0x10)) + d;
+  b = (c ^ d ^ a) + LE_32((param+0x28)) + b - 0x41404390;
+  b = ((b << 0x17) | (b >> 0x09)) + c;
+  a = (b ^ c ^ d) + LE_32((param+0x34)) + a + 0x289B7EC6;
+  a = ((a << 0x04) | (a >> 0x1c)) + b;
+  d = (a ^ b ^ c) + LE_32((param+0x00)) + d - 0x155ED806;
+  d = ((d << 0x0b) | (d >> 0x15)) + a;
+  c = (d ^ a ^ b) + LE_32((param+0x0c)) + c - 0x2B10CF7B;
+  c = ((c << 0x10) | (c >> 0x10)) + d;
+  b = (c ^ d ^ a) + LE_32((param+0x18)) + b + 0x04881D05;
+  b = ((b << 0x17) | (b >> 0x09)) + c;
+  a = (b ^ c ^ d) + LE_32((param+0x24)) + a - 0x262B2FC7;
+  a = ((a << 0x04) | (a >> 0x1c)) + b;
+  d = (a ^ b ^ c) + LE_32((param+0x30)) + d - 0x1924661B;
+  d = ((d << 0x0b) | (d >> 0x15)) + a;
+  c = (d ^ a ^ b) + LE_32((param+0x3c)) + c + 0x1fa27cf8;
+  c = ((c << 0x10) | (c >> 0x10)) + d;
+  b = (c ^ d ^ a) + LE_32((param+0x08)) + b - 0x3B53A99B;
+  b = ((b << 0x17) | (b >> 0x09)) + c;
+  
+  a = ((~d | b) ^ c)  + LE_32((param+0x00)) + a - 0x0BD6DDBC;
+  a = ((a << 0x06) | (a >> 0x1a)) + b; 
+  d = ((~c | a) ^ b)  + LE_32((param+0x1c)) + d + 0x432AFF97;
+  d = ((d << 0x0a) | (d >> 0x16)) + a; 
+  c = ((~b | d) ^ a)  + LE_32((param+0x38)) + c - 0x546BDC59;
+  c = ((c << 0x0f) | (c >> 0x11)) + d; 
+  b = ((~a | c) ^ d)  + LE_32((param+0x14)) + b - 0x036C5FC7;
+  b = ((b << 0x15) | (b >> 0x0b)) + c; 
+  a = ((~d | b) ^ c)  + LE_32((param+0x30)) + a + 0x655B59C3;
+  a = ((a << 0x06) | (a >> 0x1a)) + b; 
+  d = ((~c | a) ^ b)  + LE_32((param+0x0C)) + d - 0x70F3336E;
+  d = ((d << 0x0a) | (d >> 0x16)) + a; 
+  c = ((~b | d) ^ a)  + LE_32((param+0x28)) + c - 0x00100B83;
+  c = ((c << 0x0f) | (c >> 0x11)) + d; 
+  b = ((~a | c) ^ d)  + LE_32((param+0x04)) + b - 0x7A7BA22F;
+  b = ((b << 0x15) | (b >> 0x0b)) + c; 
+  a = ((~d | b) ^ c)  + LE_32((param+0x20)) + a + 0x6FA87E4F;
+  a = ((a << 0x06) | (a >> 0x1a)) + b; 
+  d = ((~c | a) ^ b)  + LE_32((param+0x3c)) + d - 0x01D31920;
+  d = ((d << 0x0a) | (d >> 0x16)) + a; 
+  c = ((~b | d) ^ a)  + LE_32((param+0x18)) + c - 0x5CFEBCEC;
+  c = ((c << 0x0f) | (c >> 0x11)) + d; 
+  b = ((~a | c) ^ d)  + LE_32((param+0x34)) + b + 0x4E0811A1;
+  b = ((b << 0x15) | (b >> 0x0b)) + c; 
+  a = ((~d | b) ^ c)  + LE_32((param+0x10)) + a - 0x08AC817E;
+  a = ((a << 0x06) | (a >> 0x1a)) + b; 
+  d = ((~c | a) ^ b)  + LE_32((param+0x2c)) + d - 0x42C50DCB;
+  d = ((d << 0x0a) | (d >> 0x16)) + a; 
+  c = ((~b | d) ^ a)  + LE_32((param+0x08)) + c + 0x2AD7D2BB;
+  c = ((c << 0x0f) | (c >> 0x11)) + d; 
+  b = ((~a | c) ^ d)  + LE_32((param+0x24)) + b - 0x14792C6F;
+  b = ((b << 0x15) | (b >> 0x0b)) + c; 
+
+  lprintf("hash output: %x %x %x %x\n", a, b, c, d);
+  
+  a += LE_32(field);
+  b += LE_32(field+4);
+  c += LE_32(field+8);
+  d += LE_32(field+12);
+
+  LE_32C(field, a);
+  LE_32C(field+4, b);
+  LE_32C(field+8, c);
+  LE_32C(field+12, d);
+}
+
+static void call_hash (char *key, char *challenge, int len) {
+
+  uint8_t *ptr1, *ptr2;
+  uint32_t a, b, c, d, tmp;
+  
+  ptr1=(uint8_t *) (key+16);
+  ptr2=(uint8_t *) (key+20);
+  
+  a = LE_32(ptr1);
+  b = (a >> 3) & 0x3f;
+  a += len * 8;
+  LE_32C(ptr1, a);
+  
+  if (a < (len << 3))
+  {
+    lprintf("not verified: (len << 3) > a true\n");
+    ptr2 += 4;
+  }
+
+  tmp = LE_32(ptr2) + (len >> 0x1d);
+  LE_32C(ptr2, tmp);
+  a = 64 - b;
+  c = 0;  
+  if (a <= len)
+  {
+
+    memcpy(key+b+24, challenge, a);
+    hash(key, key+24);
+    c = a;
+    d = c + 0x3f;
+    
+    while ( d < len ) {
+      lprintf("not verified:  while ( d < len )\n");
+      hash(key, challenge+d-0x3f);
+      d += 64;
+      c += 64;
+    }
+    b = 0;
+  }
+  
+  memcpy(key+b+24, challenge+c, len-c);
+}
+
+static void calc_response (char *result, char *field) {
+
+  char buf1[128];
+  char buf2[128];
+  int i;
+
+  memset (buf1, 0, 64);
+  *buf1 = 128;
+  
+  memcpy (buf2, field+16, 8);
+  
+  i = ( LE_32((buf2)) >> 3 ) & 0x3f;
+ 
+  if (i < 56) {
+    i = 56 - i;
+  } else {
+    lprintf("not verified: ! (i < 56)\n");
+    i = 120 - i;
+  }
+
+  call_hash (field, buf1, i);
+  call_hash (field, buf2, 8);
+
+  memcpy (result, field, 16);
+
+}
+
+
+static void calc_response_string (char *result, char *challenge) {
+ 
+  char field[128];
+  char zres[20];
+  int  i;
+      
+  /* initialize our field */
+  BE_32C (field,      0x01234567);
+  BE_32C ((field+4),  0x89ABCDEF);
+  BE_32C ((field+8),  0xFEDCBA98);
+  BE_32C ((field+12), 0x76543210);
+  BE_32C ((field+16), 0x00000000);
+  BE_32C ((field+20), 0x00000000);
+
+  /* calculate response */
+  call_hash(field, challenge, 64);
+  calc_response(zres,field);
+ 
+  /* convert zres to ascii string */
+  for (i=0; i<16; i++ ) {
+    char a, b;
+    
+    a = (zres[i] >> 4) & 15;
+    b = zres[i] & 15;
+
+    result[i*2]   = ((a<10) ? (a+48) : (a+87)) & 255;
+    result[i*2+1] = ((b<10) ? (b+48) : (b+87)) & 255;
+  }
+}
+
+void real_calc_response_and_checksum (char *response, char *chksum, char *challenge) {
+
+  int   ch_len, table_len, resp_len;
+  int   i;
+  char *ptr;
+  char  buf[128];
+
+  /* initialize return values */
+  memset(response, 0, 64);
+  memset(chksum, 0, 34);
+
+  /* initialize buffer */
+  memset(buf, 0, 128);
+  ptr=buf;
+  BE_32C(ptr, 0xa1e9149d);
+  ptr+=4;
+  BE_32C(ptr, 0x0e6b3b59);
+  ptr+=4;
+
+  /* some (length) checks */
+  if (challenge != NULL)
+  {
+    ch_len = strlen (challenge);
+
+    if (ch_len == 40) /* what a hack... */
+    {
+      challenge[32]=0;
+      ch_len=32;
+    }
+    if ( ch_len > 56 ) ch_len=56;
+    
+    /* copy challenge to buf */
+    memcpy(ptr, challenge, ch_len);
+  }
+  
+  if (xor_table != NULL)
+  {
+    table_len = strlen((char *) xor_table);
+
+    if (table_len > 56) table_len=56;
+
+    /* xor challenge bytewise with xor_table */
+    for (i=0; i<table_len; i++)
+      ptr[i] = ptr[i] ^ xor_table[i];
+  }
+
+  calc_response_string (response, buf);
+
+  /* add tail */
+  resp_len = strlen (response);
+  strcpy (&response[resp_len], "01d0a8e3");
+
+  /* calculate checksum */
+  for (i=0; i<resp_len/4; i++)
+    chksum[i] = response[i*4];
+}
+
+/* End of code copied from xine */
+
 static gboolean
 gst_rtspsrc_open (GstRTSPSrc * src)
 {
-  RTSPUrl *url;
   RTSPResult res;
   RTSPMessage request = { 0 };
   RTSPMessage response = { 0 };
@@ -884,22 +1191,19 @@ gst_rtspsrc_open (GstRTSPSrc * src)
   guint size;
   SDPMessage sdp = { 0 };
   GstRTSPProto protocols;
-
-  /* parse url */
-  GST_DEBUG ("parsing url...");
-  if ((res = rtsp_url_parse (src->location, &url)) < 0)
-    goto invalid_url;
+  const gchar *challenge1 = NULL;
+  gchar *value, checksum[34], challenge2[64], *s;
+  gboolean real = FALSE;
 
   /* open connection */
   GST_DEBUG ("opening connection...");
-  if ((res = rtsp_connection_open (url, &src->connection)) < 0)
+  if ((res = rtsp_connection_open (src->url, &src->connection)) < 0)
     goto could_not_open;
 
   /* create OPTIONS */
   GST_DEBUG ("create options...");
-  if ((res =
-          rtsp_message_init_request (RTSP_OPTIONS, src->location,
-              &request)) < 0)
+  if ((res = rtsp_message_init_request (&request, RTSP_OPTIONS,
+          src->location)) < 0)
     goto create_request_failed;
 
   /* send OPTIONS */
@@ -907,6 +1211,32 @@ gst_rtspsrc_open (GstRTSPSrc * src)
   if (!gst_rtspsrc_send (src, &request, &response, NULL))
     goto send_error;
 
+  /*
+   * Real servers don't follow the specification. They check for
+   * undocumented fields.
+   */
+  rtsp_message_get_header (&response, RTSP_HDR_SERVER, &s);
+  if (s && strstr (s, "Real")) {
+
+    /* Reopen the connection. Otherwise, Real servers won't cooperate. */
+    rtsp_connection_close (src->connection);
+    rtsp_connection_free (src->connection);
+    if ((res = rtsp_connection_open (src->url, &src->connection)) < 0)
+      goto could_not_open;
+
+    s = g_strdup_printf ("rtsp://%s:%d", src->url->host, src->url->port);
+    res = rtsp_message_init_request (&request, RTSP_OPTIONS, s);
+    g_free (s);
+    if (res < 0)
+      goto create_request_failed;
+    rtsp_message_add_header (&request, RTSP_HDR_USER_AGENT,
+        "RealMedia Player (" GST_PACKAGE_NAME ")");
+    rtsp_message_add_custom_header (&request, "ClientChallenge",
+        "9e26d33f2984236010ef6253fb1887f7");
+    if (!gst_rtspsrc_send (src, &request, &response, NULL))
+      goto send_error;
+  }
+
   {
     gchar *respoptions = NULL;
     gchar **options;
@@ -954,12 +1284,20 @@ gst_rtspsrc_open (GstRTSPSrc * src)
       goto no_setup;
   }
 
+  /* Again, special attention to Real servers. */
+  rtsp_message_get_custom_header (&response, "RealChallenge1", &challenge1);
+  if (challenge1) {
+    real = TRUE;
+    real_calc_response_and_checksum (challenge2, checksum, (char *) challenge1);
+    src->options |= RTSP_PLAY;
+  }
+
   /* create DESCRIBE */
   GST_DEBUG ("create describe...");
-  if ((res =
-          rtsp_message_init_request (RTSP_DESCRIBE, src->location,
-              &request)) < 0)
+  if ((res = rtsp_message_init_request (&request, RTSP_DESCRIBE,
+          src->location)) < 0)
     goto create_request_failed;
+
   /* we accept SDP for now */
   rtsp_message_add_header (&request, RTSP_HDR_ACCEPT, "application/sdp");
 
@@ -1006,7 +1344,8 @@ gst_rtspsrc_open (GstRTSPSrc * src)
 
       media = sdp_message_get_media (&sdp, i);
 
-      stream = gst_rtspsrc_create_stream (src);
+      stream = g_new0 (GstRTSPStream, 1);
+      g_hash_table_insert (src->streams, GINT_TO_POINTER (i), stream);
 
       GST_DEBUG ("setup media %d", i);
       control_url = sdp_media_get_attribute_val (media, "control");
@@ -1025,13 +1364,10 @@ gst_rtspsrc_open (GstRTSPSrc * src)
 
       GST_DEBUG ("setup %s", setup_url);
       /* create SETUP request */
-      if ((res =
-              rtsp_message_init_request (RTSP_SETUP, setup_url,
-                  &request)) < 0) {
+      res = rtsp_message_init_request (&request, RTSP_SETUP, setup_url);
         g_free (setup_url);
+      if (res < 0)
         goto create_request_failed;
-      }
-      g_free (setup_url);
 
       transports = g_strdup ("");
       if (protocols & GST_RTSP_PROTO_UDP_UNICAST) {
@@ -1040,7 +1376,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
         gchar *trxparams;
 
         /* allocate two udp ports */
-        if (!gst_rtspsrc_stream_setup_rtp (stream, media, &rtpport, &rtcpport))
+        if (!gst_rtspsrc_stream_setup_rtp (src, stream, media, &rtpport, &rtcpport))
           goto setup_rtp_failed;
 
         trxparams = g_strdup_printf ("client_port=%d-%d", rtpport, rtcpport);
@@ -1048,6 +1384,15 @@ gst_rtspsrc_open (GstRTSPSrc * src)
         g_free (trxparams);
         g_free (transports);
         transports = new;
+
+        /* For real servers, forget above stuff. */
+        if (real) {
+          g_free (transports);
+          transports = g_strdup ("x-pn-tng/tcp,rtp/avp/tcp;unicast;mode=play");
+          value = g_strdup_printf ("%s, sd=%s", challenge2, checksum);
+          rtsp_message_add_custom_header (&request, "RealChallenge2", value);
+          g_free (value);
+        }
       }
       if (protocols & GST_RTSP_PROTO_UDP_MULTICAST) {
         gchar *new;
@@ -1066,6 +1411,12 @@ gst_rtspsrc_open (GstRTSPSrc * src)
             NULL);
         g_free (transports);
         transports = new;
+
+        /* For real servers, forget above stuff. */
+        if (real) {
+          g_free (transports);
+          transports = g_strdup ("x-pn-tng/tcp,rtp/avp/tcp;unicast;mode=play");
+        }
       }
 
       /* select transport, copy is made when adding to header */
@@ -1089,7 +1440,10 @@ gst_rtspsrc_open (GstRTSPSrc * src)
         /* update allowed transports for other streams */
         if (transport.lower_transport == RTSP_LOWER_TRANS_TCP) {
           protocols = GST_RTSP_PROTO_TCP;
-          src->interleaved = TRUE;
+          if (!src->task) {
+            src->task = gst_task_create (gst_rtspsrc_loop, src);
+            gst_task_set_lock (src->task, src->task_lock);
+          }
         } else {
           if (transport.multicast) {
             /* disable unicast */
@@ -1100,7 +1454,7 @@ gst_rtspsrc_open (GstRTSPSrc * src)
           }
         }
         /* now configure the stream with the transport */
-        if (!gst_rtspsrc_stream_configure_transport (stream, &transport)) {
+        if (!gst_rtspsrc_stream_configure_transport (src, stream, &transport)) {
           GST_DEBUG ("could not configure stream transport, skipping stream");
         }
         /* clean up our transport struct */
@@ -1108,60 +1462,84 @@ gst_rtspsrc_open (GstRTSPSrc * src)
       }
     }
   }
+
+  /* Real servers need a SET_PARAMETER request. */
+  if (real) {
+    if ((res = rtsp_message_init_request (&request, RTSP_SET_PARAMETER,
+            src->location)) < 0)
+      goto create_request_failed;
+    rtsp_message_add_custom_header (&request, "Subscribe",
+        "stream=0;rule=5,stream=0;rule=6,stream=1;rule=0,stream=1;rule=1");
+    if (!gst_rtspsrc_send (src, &request, &response, NULL))
+      goto send_error;
+  }
+
+  rtsp_message_unset (&request);
+  rtsp_message_unset (&response);
   return TRUE;
 
   /* ERRORS */
-invalid_url:
-  {
-    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
-        ("Not a valid RTSP url."), (NULL));
-    return FALSE;
-  }
 could_not_open:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE,
         ("Could not open connection."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 create_request_failed:
   {
     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
         ("Could not create request."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 send_error:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Could not send message."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 no_describe:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Server does not support DESCRIBE."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 no_setup:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Server does not support SETUP."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 wrong_content_type:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Server does not support SDP."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 setup_rtp_failed:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE, ("Could not setup rtp."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 no_transport:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Server did not select transport."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 }
@@ -1178,15 +1556,15 @@ gst_rtspsrc_close (GstRTSPSrc * src)
   /* stop task if any */
   if (src->task) {
     gst_task_stop (src->task);
+    gst_task_join (src->task);
     gst_object_unref (GST_OBJECT (src->task));
     src->task = NULL;
   }
 
   if (src->options & RTSP_PLAY) {
     /* do TEARDOWN */
-    if ((res =
-            rtsp_message_init_request (RTSP_TEARDOWN, src->location,
-                &request)) < 0)
+    if ((res = rtsp_message_init_request (&request, RTSP_TEARDOWN,
+            src->location)) < 0)
       goto create_request_failed;
 
     if (!gst_rtspsrc_send (src, &request, &response, NULL))
@@ -1198,23 +1576,31 @@ gst_rtspsrc_close (GstRTSPSrc * src)
   if ((res = rtsp_connection_close (src->connection)) < 0)
     goto close_failed;
 
+  rtsp_message_unset (&request);
+  rtsp_message_unset (&response);
   return TRUE;
 
 create_request_failed:
   {
     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
         ("Could not create request."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 send_error:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Could not send message."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 close_failed:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, ("Close failed."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 }
@@ -1226,37 +1612,40 @@ gst_rtspsrc_play (GstRTSPSrc * src)
   RTSPMessage response = { 0 };
   RTSPResult res;
 
+  if (src->task)
+    gst_task_start (src->task);
+
   if (!(src->options & RTSP_PLAY))
     return TRUE;
 
   GST_DEBUG ("PLAY...");
 
   /* do play */
-  if ((res =
-          rtsp_message_init_request (RTSP_PLAY, src->location, &request)) < 0)
+  if ((res = rtsp_message_init_request (&request, RTSP_PLAY,
+          src->location)) < 0)
     goto create_request_failed;
 
   if (!gst_rtspsrc_send (src, &request, &response, NULL))
     goto send_error;
 
-  if (src->interleaved) {
-    src->task = gst_task_create ((GstTaskFunction) gst_rtspsrc_loop, src);
-
-    gst_task_start (src->task);
-  }
-
+  rtsp_message_unset (&request);
+  rtsp_message_unset (&response);
   return TRUE;
 
 create_request_failed:
   {
     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
         ("Could not create request."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 send_error:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Could not send message."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 }
@@ -1268,30 +1657,39 @@ gst_rtspsrc_pause (GstRTSPSrc * src)
   RTSPMessage response = { 0 };
   RTSPResult res;
 
+  if (src->task)
+    gst_task_pause (src->task);
+
   if (!(src->options & RTSP_PAUSE))
     return TRUE;
 
   GST_DEBUG ("PAUSE...");
   /* do pause */
-  if ((res =
-          rtsp_message_init_request (RTSP_PAUSE, src->location, &request)) < 0)
+  if ((res = rtsp_message_init_request (&request, RTSP_PAUSE,
+          src->location)) < 0)
     goto create_request_failed;
 
   if (!gst_rtspsrc_send (src, &request, &response, NULL))
     goto send_error;
 
+  rtsp_message_unset (&request);
+  rtsp_message_unset (&response);
   return TRUE;
 
 create_request_failed:
   {
     GST_ELEMENT_ERROR (src, LIBRARY, INIT,
         ("Could not create request."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 send_error:
   {
     GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
         ("Could not send message."), (NULL));
+    rtsp_message_unset (&request);
+    rtsp_message_unset (&response);
     return FALSE;
   }
 }
@@ -1309,7 +1706,6 @@ gst_rtspsrc_change_state (GstElement * e
     case GST_STATE_CHANGE_NULL_TO_READY:
       break;
     case GST_STATE_CHANGE_READY_TO_PAUSED:
-      rtspsrc->interleaved = FALSE;
       rtspsrc->options = 0;
       if (!gst_rtspsrc_open (rtspsrc))
         goto open_failed;
@@ -1325,10 +1721,6 @@ gst_rtspsrc_change_state (GstElement * e
   if (ret == GST_STATE_CHANGE_FAILURE)
     goto done;
 
-  ret = gst_rtspsrc_set_state (rtspsrc, GST_STATE_PENDING (rtspsrc));
-  if (ret == GST_STATE_CHANGE_FAILURE)
-    goto done;
-
   switch (transition) {
     case GST_STATE_CHANGE_READY_TO_PAUSED:
       ret = GST_STATE_CHANGE_NO_PREROLL;
@@ -1374,14 +1766,24 @@ gst_rtspsrc_uri_get_uri (GstURIHandler *
 {
   GstRTSPSrc *src = GST_RTSPSRC (handler);
 
-  return g_strdup (src->location);
+  return src->location;
 }
 
 static gboolean
 gst_rtspsrc_uri_set_uri (GstURIHandler * handler, const gchar * uri)
 {
   GstRTSPSrc *src = GST_RTSPSRC (handler);
+  RTSPResult res;
+
+  if (src->location && uri && !strcmp (uri, src->location))
+    return TRUE;
 
+  rtsp_url_free (src->url);
+  if ((res = rtsp_url_parse (uri, &src->url)) < 0) {
+    GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
+        ("Not a valid RTSP url."), (NULL));
+    return FALSE;
+  }
   g_free (src->location);
   src->location = g_strdup (uri);
 
Index: gstrtspsrc.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/gstrtspsrc.h,v
retrieving revision 1.8
diff -u -3 -p -b -B -d -r1.8 gstrtspsrc.h
--- gstrtspsrc.h	20 Jun 2006 14:57:09 -0000	1.8
+++ gstrtspsrc.h	22 Jul 2006 21:41:29 -0000
@@ -53,20 +53,11 @@ typedef enum
 typedef struct _GstRTSPStream GstRTSPStream;
 
 struct _GstRTSPStream {
-  gint        id;
-
-  gint        rtpchannel;
-  gint        rtcpchannel;
-
-  GstRTSPSrc *parent;
 
   /* our udp sources */
   GstElement *rtpsrc;
   GstElement *rtcpsrc;
 
-  /* our udp sink back to the server */
-  GstElement *rtcpsink;
-
   /* the rtp decoder */
   GstElement *rtpdec;
   GstPad     *rtpdecrtp;
@@ -74,14 +65,14 @@ struct _GstRTSPStream {
 };
 
 struct _GstRTSPSrc {
-  GstElement element;
+  GstBin element;
 
-  gboolean       interleaved;
-  GstTask       *task;
+  GstTask         *task; /* interleaved */
+  GStaticRecMutex *task_lock;
 
-  gint           numstreams;
-  GList         *streams;
+  GHashTable    *streams;
 
+  RTSPUrl       *url;
   gchar         *location;
   gboolean       debug;
   guint 	 retry;
@@ -96,7 +87,7 @@ struct _GstRTSPSrc {
 };
 
 struct _GstRTSPSrcClass {
-  GstElementClass parent_class;
+  GstBinClass parent_class;
 };
 
 GType gst_rtspsrc_get_type(void);
Index: rtspconnection.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspconnection.c,v
retrieving revision 1.13
diff -u -3 -p -b -B -d -r1.13 rtspconnection.c
--- rtspconnection.c	10 Jul 2006 16:41:57 -0000	1.13
+++ rtspconnection.c	22 Jul 2006 21:41:29 -0000
@@ -135,7 +135,6 @@ rtsp_connection_create (gint fd, RTSPCon
   newconn->fd = fd;
   newconn->cseq = 0;
   newconn->session_id[0] = 0;
-  newconn->state = RTSP_STATE_INIT;
 
   *conn = newconn;
 
@@ -150,6 +149,13 @@ append_header (gint key, gchar * value, 
   g_string_append_printf (str, "%s: %s\r\n", keystr, value);
 }
 
+static void
+append_custom_header (gpointer key, gpointer value, gpointer data)
+{
+  g_string_append_printf ((GString *) data, "%s: %s\r\n", (gchar *) key,
+      (gchar *) value);
+}
+
 RTSPResult
 rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
 {
@@ -171,6 +177,12 @@ rtsp_connection_send (RTSPConnection * c
     goto version_error;
 #endif
 
+  data = g_strdup_printf ("%s %s RTSP/1.0\r\n",
+      rtsp_method_as_text (message->type_data.request.method),
+      message->type_data.request.uri);
+  write (conn->fd, data, strlen (data));
+  g_free (data);
+  
   str = g_string_new ("");
 
   /* create request string, add CSeq */
@@ -186,6 +198,7 @@ rtsp_connection_send (RTSPConnection * c
 
   /* append headers */
   g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
+    g_hash_table_foreach (message->custom_hdr_fields, append_custom_header, str);
 
   /* append Content-Length and body if needed */
   if (message->body != NULL && message->body_size > 0) {
@@ -334,7 +347,7 @@ parse_response_status (gchar * buffer, R
   while (g_ascii_isspace (*bptr))
     bptr++;
 
-  rtsp_message_init_response (code, bptr, NULL, msg);
+  rtsp_message_init_response (msg, code, bptr, NULL);
 
   return RTSP_OK;
 
@@ -366,7 +379,7 @@ parse_request_line (gchar * buffer, RTSP
   if (strcmp (versionstr, "RTSP/1.0") != 0)
     goto wrong_version;
 
-  rtsp_message_init_request (method, urlstr, msg);
+  rtsp_message_init_request (msg, method, urlstr);
 
   return RTSP_OK;
 
@@ -398,11 +411,12 @@ parse_line (gchar * buffer, RTSPMessage 
   bptr++;
 
   field = rtsp_find_header_field (key);
-  if (field != -1) {
     while (g_ascii_isspace (*bptr))
       bptr++;
+  if (field != -1)
     rtsp_message_add_header (msg, field, bptr);
-  }
+  else
+    rtsp_message_add_custom_header (msg, key, bptr);
 
   return RTSP_OK;
 }
@@ -491,7 +505,7 @@ rtsp_connection_receive (RTSPConnection 
         goto error;
 
       /* now we create a data message */
-      rtsp_message_init_data ((gint) c, msg);
+      rtsp_message_init_data (msg, (gint) c);
 
       /* next two bytes are the length of the data */
       ret = read (conn->fd, &size, 2);
Index: rtspconnection.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspconnection.h,v
retrieving revision 1.4
diff -u -3 -p -b -B -d -r1.4 rtspconnection.h
--- rtspconnection.h	6 Dec 2005 19:44:55 -0000	1.4
+++ rtspconnection.h	22 Jul 2006 21:41:29 -0000
@@ -34,8 +34,6 @@ typedef struct _RTSPConnection
 
   gint          cseq;                   /* sequence number */
   gchar         session_id[512];        /* session id */
-  
-  RTSPState     state;                  /* state of the connection */
 } RTSPConnection;
 
 /* opening/closing a connection */
Index: rtspdefs.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspdefs.h,v
retrieving revision 1.6
diff -u -3 -p -b -B -d -r1.6 rtspdefs.h
--- rtspdefs.h	10 Jul 2006 16:41:57 -0000	1.6
+++ rtspdefs.h	22 Jul 2006 21:41:30 -0000
@@ -50,13 +50,6 @@ typedef enum {
 } RTSPFamily;
 
 typedef enum {
-  RTSP_STATE_INIT,
-  RTSP_STATE_READY,
-  RTSP_STATE_PLAYING,
-  RTSP_STATE_RECORDING,
-} RTSPState;
-
-typedef enum {
   RTSP_DESCRIBE         = (1 <<  0),
   RTSP_ANNOUNCE         = (1 <<  1),
   RTSP_GET_PARAMETER    = (1 <<  2),
Index: rtspmessage.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspmessage.c,v
retrieving revision 1.4
diff -u -3 -p -b -B -d -r1.4 rtspmessage.c
--- rtspmessage.c	9 Feb 2006 14:20:14 -0000	1.4
+++ rtspmessage.c	22 Jul 2006 21:41:30 -0000
@@ -20,35 +20,32 @@
 #include "rtspmessage.h"
 
 RTSPResult
-rtsp_message_new_request (RTSPMethod method, gchar * uri, RTSPMessage ** msg)
-{
-  RTSPMessage *newmsg;
-
-  if (msg == NULL || uri == NULL)
-    return RTSP_EINVAL;
-
-  newmsg = g_new0 (RTSPMessage, 1);
-
-  *msg = newmsg;
-
-  return rtsp_message_init_request (method, uri, newmsg);
-}
-
-RTSPResult
-rtsp_message_init_request (RTSPMethod method, gchar * uri, RTSPMessage * msg)
+rtsp_message_unset (RTSPMessage * msg)
 {
-  if (msg == NULL || uri == NULL)
+  if (!msg)
     return RTSP_EINVAL;
 
-  msg->type = RTSP_MESSAGE_REQUEST;
-  msg->type_data.request.method = method;
-  g_free (msg->type_data.request.uri);
-  msg->type_data.request.uri = g_strdup (uri);
-
   if (msg->hdr_fields != NULL)
     g_hash_table_destroy (msg->hdr_fields);
-  msg->hdr_fields =
-      g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+  if (msg->custom_hdr_fields != NULL)
+    g_hash_table_destroy (msg->custom_hdr_fields);
+
+  switch (msg->type) {
+    case RTSP_MESSAGE_REQUEST:
+      if (msg->type_data.request.uri) {
+        g_free (msg->type_data.request.uri);
+        msg->type_data.request.uri = NULL;
+      }
+      break;
+    case RTSP_MESSAGE_RESPONSE:
+      if (msg->type_data.response.reason) {
+        g_free (msg->type_data.response.reason);
+        msg->type_data.response.reason = NULL;
+      }
+      break;
+    default:
+      break;
+  }
 
   if (msg->body) {
     g_free (msg->body);
@@ -60,43 +57,43 @@ rtsp_message_init_request (RTSPMethod me
 }
 
 RTSPResult
-rtsp_message_new_response (RTSPStatusCode code, gchar * reason,
-    RTSPMessage * request, RTSPMessage ** msg)
+rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method, gchar * uri)
 {
-  RTSPMessage *newmsg;
-
-  if (msg == NULL || reason == NULL || request == NULL)
+  if (msg == NULL || uri == NULL)
     return RTSP_EINVAL;
 
-  newmsg = g_new0 (RTSPMessage, 1);
+  rtsp_message_unset (msg);
 
-  *msg = newmsg;
+  msg->type = RTSP_MESSAGE_REQUEST;
+  msg->type_data.request.method = method;
+  msg->type_data.request.uri = g_strdup (uri);
 
-  return rtsp_message_init_response (code, reason, request, newmsg);
+  msg->hdr_fields =
+      g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
+  msg->custom_hdr_fields =
+    g_hash_table_new (g_str_hash, g_str_equal);
+
+  return RTSP_OK;
 }
 
 RTSPResult
-rtsp_message_init_response (RTSPStatusCode code, gchar * reason,
-    RTSPMessage * request, RTSPMessage * msg)
+rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
+    gchar * reason, RTSPMessage * request)
 {
   if (reason == NULL || msg == NULL)
     return RTSP_EINVAL;
 
+  rtsp_message_unset (msg);
+
   msg->type = RTSP_MESSAGE_RESPONSE;
   msg->type_data.response.code = code;
   g_free (msg->type_data.response.reason);
   msg->type_data.response.reason = g_strdup (reason);
 
-  if (msg->hdr_fields != NULL)
-    g_hash_table_destroy (msg->hdr_fields);
   msg->hdr_fields =
       g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
-
-  if (msg->body) {
-    g_free (msg->body);
-    msg->body = NULL;
-  }
-  msg->body_size = 0;
+  msg->custom_hdr_fields =
+    g_hash_table_new (g_str_hash, g_str_equal);
 
   if (request) {
     /* FIXME copy headers */
@@ -106,11 +103,13 @@ rtsp_message_init_response (RTSPStatusCo
 }
 
 RTSPResult
-rtsp_message_init_data (gint channel, RTSPMessage * msg)
+rtsp_message_init_data (RTSPMessage * msg, gint channel)
 {
   if (msg == NULL)
     return RTSP_EINVAL;
 
+  rtsp_message_unset (msg);
+
   msg->type = RTSP_MESSAGE_DATA;
   msg->type_data.data.channel = channel;
 
@@ -139,7 +138,7 @@ rtsp_message_remove_header (RTSPMessage 
 
   g_hash_table_remove (msg->hdr_fields, GINT_TO_POINTER (field));
 
-  return RTSP_ENOTIMPL;
+  return RTSP_OK;
 }
 
 RTSPResult
@@ -161,6 +160,48 @@ rtsp_message_get_header (RTSPMessage * m
 }
 
 RTSPResult
+rtsp_message_add_custom_header (RTSPMessage * msg, const gchar * field,
+    const gchar * value)
+{
+  if (msg == NULL || field == NULL || value == NULL)
+    return RTSP_EINVAL;
+
+  g_hash_table_insert (msg->custom_hdr_fields, g_strdup (field),
+      g_strdup (value));
+
+  return RTSP_OK;
+}
+
+RTSPResult
+rtsp_message_remove_custom_header (RTSPMessage * msg, const gchar * field)
+{
+  if (msg == NULL || field == NULL)
+    return RTSP_EINVAL;
+
+  g_hash_table_remove (msg->custom_hdr_fields, field);
+
+  return RTSP_OK;
+}
+
+RTSPResult
+rtsp_message_get_custom_header (RTSPMessage * msg, const gchar * field,
+    const gchar ** value)
+{
+  gchar *val;
+
+  if (msg == NULL || field == NULL || value == NULL)
+    return RTSP_EINVAL;
+
+  val = g_hash_table_lookup (msg->custom_hdr_fields, field);
+  if (val == NULL)
+    return RTSP_ENOTIMPL;
+
+  *value = val;
+
+  return RTSP_OK;
+}
+
+RTSPResult
 rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
 {
   if (msg == NULL)
@@ -236,6 +277,12 @@ dump_key_value (gpointer key, gpointer v
       (gchar *) value);
 }
 
+static void
+dump_custom_key_value (gpointer key, gpointer value, gpointer data)
+{
+  g_print ("   key: '%s', value: '%s'\n", (gchar *) key, (gchar *) value);
+}
+
 RTSPResult
 rtsp_message_dump (RTSPMessage * msg)
 {
@@ -253,6 +300,7 @@ rtsp_message_dump (RTSPMessage * msg)
     g_print ("   uri:    '%s'\n", msg->type_data.request.uri);
     g_print (" headers:\n");
     g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
+    g_hash_table_foreach (msg->custom_hdr_fields, dump_custom_key_value, NULL);
     g_print (" body:\n");
     rtsp_message_get_body (msg, &data, &size);
     dump_mem (data, size);
@@ -263,6 +311,7 @@ rtsp_message_dump (RTSPMessage * msg)
     g_print ("   reason: '%s'\n", msg->type_data.response.reason);
     g_print (" headers:\n");
     g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
+    g_hash_table_foreach (msg->custom_hdr_fields, dump_custom_key_value, NULL);
     rtsp_message_get_body (msg, &data, &size);
     g_print (" body: length %d\n", size);
     dump_mem (data, size);
Index: rtspmessage.h
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspmessage.h,v
retrieving revision 1.4
diff -u -3 -p -b -B -d -r1.4 rtspmessage.h
--- rtspmessage.h	6 Dec 2005 19:44:55 -0000	1.4
+++ rtspmessage.h	22 Jul 2006 21:41:30 -0000
@@ -52,28 +52,27 @@ typedef struct _RTSPMessage
   } type_data;
 
   GHashTable    *hdr_fields;
+  GHashTable    *custom_hdr_fields;
 
   guint8        *body;
   guint          body_size;
 
 } RTSPMessage;
 
-RTSPResult      rtsp_message_new_request        (RTSPMethod method, gchar *uri, RTSPMessage **msg);
-RTSPResult      rtsp_message_init_request       (RTSPMethod method, gchar *uri, RTSPMessage *msg);
-
-RTSPResult      rtsp_message_new_response       (RTSPStatusCode code, gchar *reason, 
-                                                 RTSPMessage *request, RTSPMessage **msg);
-RTSPResult      rtsp_message_init_response      (RTSPStatusCode code, gchar *reason, 
-                                                 RTSPMessage *request, RTSPMessage *msg);
-RTSPResult      rtsp_message_init_data          (gint channel, RTSPMessage *msg);
-
-RTSPResult      rtsp_message_free               (RTSPMessage *msg);
+RTSPResult rtsp_message_init_request  (RTSPMessage *msg, RTSPMethod method, gchar *uri);
+RTSPResult rtsp_message_init_response (RTSPMessage *msg, RTSPStatusCode code, gchar *reason, RTSPMessage *response);
+RTSPResult rtsp_message_init_data     (RTSPMessage *msg, gint channel);
+RTSPResult rtsp_message_unset         (RTSPMessage *msg);
 
 
 RTSPResult      rtsp_message_add_header         (RTSPMessage *msg, RTSPHeaderField field, gchar *value);
 RTSPResult      rtsp_message_remove_header      (RTSPMessage *msg, RTSPHeaderField field);
 RTSPResult      rtsp_message_get_header         (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
 
+RTSPResult rtsp_message_add_custom_header    (RTSPMessage *msg, const gchar *field, const gchar *value);
+RTSPResult rtsp_message_remove_custom_header (RTSPMessage *msg, const gchar *field);
+RTSPResult rtsp_message_get_custom_header    (RTSPMessage *msg, const gchar *field, const gchar **value);
+
 RTSPResult      rtsp_message_set_body           (RTSPMessage *msg, guint8 *data, guint size);
 RTSPResult      rtsp_message_take_body          (RTSPMessage *msg, guint8 *data, guint size);
 RTSPResult      rtsp_message_get_body           (RTSPMessage *msg, guint8 **data, guint *size);
Index: rtsptransport.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtsptransport.c,v
retrieving revision 1.5
diff -u -3 -p -b -B -d -r1.5 rtsptransport.c
--- rtsptransport.c	15 Feb 2006 10:15:47 -0000	1.5
+++ rtsptransport.c	22 Jul 2006 21:41:30 -0000
@@ -100,6 +100,8 @@ rtsp_transport_parse (gchar * str, RTSPT
       transport->lower_transport = RTSP_LOWER_TRANS_TCP;
     } else if (g_str_has_prefix (split[i], "rtp/avp")) {
       transport->lower_transport = RTSP_LOWER_TRANS_UDP;
+    } else if (g_str_has_prefix (split[i], "x-pn-tng/tcp")) {
+      transport->lower_transport = RTSP_LOWER_TRANS_TCP;
     } else if (g_str_has_prefix (split[i], "multicast")) {
       transport->multicast = TRUE;
     } else if (g_str_has_prefix (split[i], "unicast")) {
Index: rtspurl.c
===================================================================
RCS file: /cvs/gstreamer/gst-plugins-good/gst/rtsp/rtspurl.c,v
retrieving revision 1.6
diff -u -3 -p -b -B -d -r1.6 rtspurl.c
--- rtspurl.c	8 May 2006 14:35:20 -0000	1.6
+++ rtspurl.c	22 Jul 2006 21:41:30 -0000
@@ -104,6 +104,8 @@ invalid:
 void
 rtsp_url_free (RTSPUrl * url)
 {
+  if (!url)
+    return;
   g_free (url->user);
   g_free (url->passwd);
   g_free (url->host);
