Move SDP and RTSP from helper objects in -good to a reusable library.
authorWim Taymans <wim.taymans@gmail.com>
Tue, 24 Jul 2007 11:52:56 +0000 (11:52 +0000)
committerWim Taymans <wim.taymans@gmail.com>
Tue, 24 Jul 2007 11:52:56 +0000 (11:52 +0000)
Original commit message from CVS:
* configure.ac:
* gst-libs/gst/Makefile.am:
* gst-libs/gst/rtsp/Makefile.am:
* gst-libs/gst/rtsp/gstrtspbase64.c: (gst_rtsp_base64_encode):
* gst-libs/gst/rtsp/gstrtspbase64.h:
* gst-libs/gst/rtsp/gstrtspconnection.c: (inet_aton),
(gst_rtsp_connection_create), (gst_rtsp_connection_connect),
(add_auth_header), (add_date_header), (gst_rtsp_connection_write),
(gst_rtsp_connection_send), (read_line), (read_string), (read_key),
(parse_response_status), (parse_request_line), (parse_line),
(gst_rtsp_connection_read), (read_body),
(gst_rtsp_connection_receive), (gst_rtsp_connection_close),
(gst_rtsp_connection_free), (gst_rtsp_connection_next_timeout),
(gst_rtsp_connection_reset_timeout), (gst_rtsp_connection_flush),
(gst_rtsp_connection_set_auth):
* gst-libs/gst/rtsp/gstrtspconnection.h:
* gst-libs/gst/rtsp/gstrtspdefs.c: (rtsp_init_status),
(gst_rtsp_strresult), (gst_rtsp_method_as_text),
(gst_rtsp_version_as_text), (gst_rtsp_header_as_text),
(gst_rtsp_status_as_text), (gst_rtsp_find_header_field),
(gst_rtsp_find_method):
* gst-libs/gst/rtsp/gstrtspdefs.h:
* gst-libs/gst/rtsp/gstrtspmessage.c: (key_value_foreach),
(gst_rtsp_message_new), (gst_rtsp_message_init),
(gst_rtsp_message_new_request), (gst_rtsp_message_init_request),
(gst_rtsp_message_new_response), (gst_rtsp_message_init_response),
(gst_rtsp_message_init_data), (gst_rtsp_message_unset),
(gst_rtsp_message_free), (gst_rtsp_message_add_header),
(gst_rtsp_message_remove_header), (gst_rtsp_message_get_header),
(gst_rtsp_message_append_headers), (gst_rtsp_message_set_body),
(gst_rtsp_message_take_body), (gst_rtsp_message_get_body),
(gst_rtsp_message_steal_body), (dump_mem), (dump_key_value),
(gst_rtsp_message_dump):
* gst-libs/gst/rtsp/gstrtspmessage.h:
* gst-libs/gst/rtsp/gstrtsprange.c: (parse_npt_time),
(parse_npt_range), (parse_clock_range), (parse_smpte_range),
(gst_rtsp_range_parse), (gst_rtsp_range_free):
* gst-libs/gst/rtsp/gstrtsprange.h:
* gst-libs/gst/rtsp/gstrtsptransport.c: (gst_rtsp_transport_new),
(gst_rtsp_transport_init), (gst_rtsp_transport_get_mime),
(gst_rtsp_transport_get_manager), (parse_mode), (parse_range),
(range_as_text), (rtsp_transport_mode_as_text),
(rtsp_transport_profile_as_text), (rtsp_transport_ltrans_as_text),
(gst_rtsp_transport_parse), (gst_rtsp_transport_as_text),
(gst_rtsp_transport_free):
* gst-libs/gst/rtsp/gstrtsptransport.h:
* gst-libs/gst/rtsp/gstrtspurl.c: (gst_rtsp_url_parse),
(gst_rtsp_url_free), (gst_rtsp_url_set_port),
(gst_rtsp_url_get_port), (gst_rtsp_url_get_request_uri):
* gst-libs/gst/rtsp/gstrtspurl.h:
* gst-libs/gst/sdp/Makefile.am:
* gst-libs/gst/sdp/gstsdp.h:
* gst-libs/gst/sdp/gstsdpmessage.c: (gst_sdp_origin_init),
(gst_sdp_connection_init), (gst_sdp_bandwidth_init),
(gst_sdp_time_init), (gst_sdp_zone_init), (gst_sdp_key_init),
(gst_sdp_attribute_init), (gst_sdp_message_new),
(gst_sdp_message_init), (gst_sdp_message_uninit),
(gst_sdp_message_free), (gst_sdp_media_new), (gst_sdp_media_init),
(gst_sdp_media_uninit), (gst_sdp_media_free),
(gst_sdp_message_set_origin), (gst_sdp_message_get_origin),
(gst_sdp_message_set_connection), (gst_sdp_message_get_connection),
(gst_sdp_message_add_bandwidth), (gst_sdp_message_add_time),
(gst_sdp_message_add_zone), (gst_sdp_message_set_key),
(gst_sdp_message_get_key), (gst_sdp_message_get_attribute_val_n),
(gst_sdp_message_get_attribute_val),
(gst_sdp_message_add_attribute), (gst_sdp_message_add_media),
(gst_sdp_media_add_attribute), (gst_sdp_media_add_bandwidth),
(gst_sdp_media_add_format), (gst_sdp_media_get_attribute),
(gst_sdp_media_get_attribute_val_n),
(gst_sdp_media_get_attribute_val), (gst_sdp_media_get_format),
(read_string), (read_string_del), (gst_sdp_parse_line),
(gst_sdp_message_parse_buffer), (print_media),
(gst_sdp_message_dump):
* gst-libs/gst/sdp/gstsdpmessage.h:
* pkgconfig/gstreamer-plugins-base-uninstalled.pc.in:
Move SDP and RTSP from helper objects in -good to a reusable library.
Use a proper gst_ namespace.

23 files changed:
ChangeLog
configure.ac
gst-libs/gst/Makefile.am
gst-libs/gst/rtsp/Makefile.am [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspbase64.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspbase64.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspconnection.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspconnection.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspdefs.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspdefs.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspmessage.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspmessage.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtsprange.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtsprange.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtsptransport.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtsptransport.h [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspurl.c [new file with mode: 0644]
gst-libs/gst/rtsp/gstrtspurl.h [new file with mode: 0644]
gst-libs/gst/sdp/Makefile.am [new file with mode: 0644]
gst-libs/gst/sdp/gstsdp.h [new file with mode: 0644]
gst-libs/gst/sdp/gstsdpmessage.c [new file with mode: 0644]
gst-libs/gst/sdp/gstsdpmessage.h [new file with mode: 0644]
pkgconfig/gstreamer-plugins-base-uninstalled.pc.in

index 35dcccc..c756e79 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,83 @@
+2007-07-24  Wim Taymans  <wim.taymans@gmail.com>
+
+       * configure.ac:
+       * gst-libs/gst/Makefile.am:
+       * gst-libs/gst/rtsp/Makefile.am:
+       * gst-libs/gst/rtsp/gstrtspbase64.c: (gst_rtsp_base64_encode):
+       * gst-libs/gst/rtsp/gstrtspbase64.h:
+       * gst-libs/gst/rtsp/gstrtspconnection.c: (inet_aton),
+       (gst_rtsp_connection_create), (gst_rtsp_connection_connect),
+       (add_auth_header), (add_date_header), (gst_rtsp_connection_write),
+       (gst_rtsp_connection_send), (read_line), (read_string), (read_key),
+       (parse_response_status), (parse_request_line), (parse_line),
+       (gst_rtsp_connection_read), (read_body),
+       (gst_rtsp_connection_receive), (gst_rtsp_connection_close),
+       (gst_rtsp_connection_free), (gst_rtsp_connection_next_timeout),
+       (gst_rtsp_connection_reset_timeout), (gst_rtsp_connection_flush),
+       (gst_rtsp_connection_set_auth):
+       * gst-libs/gst/rtsp/gstrtspconnection.h:
+       * gst-libs/gst/rtsp/gstrtspdefs.c: (rtsp_init_status),
+       (gst_rtsp_strresult), (gst_rtsp_method_as_text),
+       (gst_rtsp_version_as_text), (gst_rtsp_header_as_text),
+       (gst_rtsp_status_as_text), (gst_rtsp_find_header_field),
+       (gst_rtsp_find_method):
+       * gst-libs/gst/rtsp/gstrtspdefs.h:
+       * gst-libs/gst/rtsp/gstrtspmessage.c: (key_value_foreach),
+       (gst_rtsp_message_new), (gst_rtsp_message_init),
+       (gst_rtsp_message_new_request), (gst_rtsp_message_init_request),
+       (gst_rtsp_message_new_response), (gst_rtsp_message_init_response),
+       (gst_rtsp_message_init_data), (gst_rtsp_message_unset),
+       (gst_rtsp_message_free), (gst_rtsp_message_add_header),
+       (gst_rtsp_message_remove_header), (gst_rtsp_message_get_header),
+       (gst_rtsp_message_append_headers), (gst_rtsp_message_set_body),
+       (gst_rtsp_message_take_body), (gst_rtsp_message_get_body),
+       (gst_rtsp_message_steal_body), (dump_mem), (dump_key_value),
+       (gst_rtsp_message_dump):
+       * gst-libs/gst/rtsp/gstrtspmessage.h:
+       * gst-libs/gst/rtsp/gstrtsprange.c: (parse_npt_time),
+       (parse_npt_range), (parse_clock_range), (parse_smpte_range),
+       (gst_rtsp_range_parse), (gst_rtsp_range_free):
+       * gst-libs/gst/rtsp/gstrtsprange.h:
+       * gst-libs/gst/rtsp/gstrtsptransport.c: (gst_rtsp_transport_new),
+       (gst_rtsp_transport_init), (gst_rtsp_transport_get_mime),
+       (gst_rtsp_transport_get_manager), (parse_mode), (parse_range),
+       (range_as_text), (rtsp_transport_mode_as_text),
+       (rtsp_transport_profile_as_text), (rtsp_transport_ltrans_as_text),
+       (gst_rtsp_transport_parse), (gst_rtsp_transport_as_text),
+       (gst_rtsp_transport_free):
+       * gst-libs/gst/rtsp/gstrtsptransport.h:
+       * gst-libs/gst/rtsp/gstrtspurl.c: (gst_rtsp_url_parse),
+       (gst_rtsp_url_free), (gst_rtsp_url_set_port),
+       (gst_rtsp_url_get_port), (gst_rtsp_url_get_request_uri):
+       * gst-libs/gst/rtsp/gstrtspurl.h:
+       * gst-libs/gst/sdp/Makefile.am:
+       * gst-libs/gst/sdp/gstsdp.h:
+       * gst-libs/gst/sdp/gstsdpmessage.c: (gst_sdp_origin_init),
+       (gst_sdp_connection_init), (gst_sdp_bandwidth_init),
+       (gst_sdp_time_init), (gst_sdp_zone_init), (gst_sdp_key_init),
+       (gst_sdp_attribute_init), (gst_sdp_message_new),
+       (gst_sdp_message_init), (gst_sdp_message_uninit),
+       (gst_sdp_message_free), (gst_sdp_media_new), (gst_sdp_media_init),
+       (gst_sdp_media_uninit), (gst_sdp_media_free),
+       (gst_sdp_message_set_origin), (gst_sdp_message_get_origin),
+       (gst_sdp_message_set_connection), (gst_sdp_message_get_connection),
+       (gst_sdp_message_add_bandwidth), (gst_sdp_message_add_time),
+       (gst_sdp_message_add_zone), (gst_sdp_message_set_key),
+       (gst_sdp_message_get_key), (gst_sdp_message_get_attribute_val_n),
+       (gst_sdp_message_get_attribute_val),
+       (gst_sdp_message_add_attribute), (gst_sdp_message_add_media),
+       (gst_sdp_media_add_attribute), (gst_sdp_media_add_bandwidth),
+       (gst_sdp_media_add_format), (gst_sdp_media_get_attribute),
+       (gst_sdp_media_get_attribute_val_n),
+       (gst_sdp_media_get_attribute_val), (gst_sdp_media_get_format),
+       (read_string), (read_string_del), (gst_sdp_parse_line),
+       (gst_sdp_message_parse_buffer), (print_media),
+       (gst_sdp_message_dump):
+       * gst-libs/gst/sdp/gstsdpmessage.h:
+       * pkgconfig/gstreamer-plugins-base-uninstalled.pc.in:
+       Move SDP and RTSP from helper objects in -good to a reusable library.
+       Use a proper gst_ namespace.
+
 2007-07-23  Sebastian Dröge  <slomo@circular-chaos.org>
 
        * ext/vorbis/vorbisdec.c: (vorbis_dec_push_forward),
index 3bf6d85..58503f9 100644 (file)
@@ -646,6 +646,8 @@ gst-libs/gst/interfaces/Makefile
 gst-libs/gst/netbuffer/Makefile
 gst-libs/gst/riff/Makefile
 gst-libs/gst/rtp/Makefile
+gst-libs/gst/rtsp/Makefile
+gst-libs/gst/sdp/Makefile
 gst-libs/gst/tag/Makefile
 gst-libs/gst/pbutils/Makefile
 gst-libs/gst/video/Makefile
index f1fd4c3..f4db55a 100644 (file)
@@ -12,6 +12,8 @@ SUBDIRS = \
        pbutils \
        riff \
        rtp \
+       rtsp \
+       sdp \
        video
 
 noinst_HEADERS = gettext.h gst-i18n-plugin.h
diff --git a/gst-libs/gst/rtsp/Makefile.am b/gst-libs/gst/rtsp/Makefile.am
new file mode 100644 (file)
index 0000000..38763ba
--- /dev/null
@@ -0,0 +1,29 @@
+libgstrtspincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/rtsp
+
+libgstrtspinclude_HEADERS = gstrtspbase64.h \
+                           gstrtspconnection.h \
+                           gstrtspdefs.h       \
+                           gstrtspmessage.h    \
+                           gstrtsprange.h      \
+                           gstrtsptransport.h  \
+                           gstrtspurl.h 
+
+#gstrtspextreal.h    
+#gstrtspextwms.h     
+
+lib_LTLIBRARIES = libgstrtsp-@GST_MAJORMINOR@.la
+
+libgstrtsp_@GST_MAJORMINOR@_la_SOURCES = gstrtspbase64.c \
+                                         gstrtspconnection.c \
+                                         gstrtspdefs.c       \
+                                        gstrtspmessage.c    \
+                                        gstrtsprange.c      \
+                                        gstrtsptransport.c  \
+                                        gstrtspurl.c 
+
+#gstrtspextwms.c  
+#rtspextreal.c    
+
+libgstrtsp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstrtsp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstrtsp_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
diff --git a/gst-libs/gst/rtsp/gstrtspbase64.c b/gst-libs/gst/rtsp/gstrtspbase64.c
new file mode 100644 (file)
index 0000000..253004a
--- /dev/null
@@ -0,0 +1,70 @@
+/* GStreamer
+ * Copyright (C) <2007> Mike Smith <msmith@xiph.org>
+ *
+ * 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "gstrtspbase64.h"
+
+static char base64table[64] = {
+  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O',
+  'P',
+  'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e',
+  'f',
+  'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u',
+  'v',
+  'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
+};
+
+/* This isn't efficient, but it doesn't need to be */
+gchar *
+gst_rtsp_base64_encode (gchar * data, gint len)
+{
+  gchar *out = g_malloc (len * 4 / 3 + 4);
+  gchar *result = out;
+  int chunk;
+
+  while (len > 0) {
+    chunk = (len > 3) ? 3 : len;
+    *out++ = base64table[(*data & 0xFC) >> 2];
+    *out++ = base64table[((*data & 0x03) << 4) | ((*(data + 1) & 0xF0) >> 4)];
+    switch (chunk) {
+      case 3:
+        *out++ =
+            base64table[((*(data + 1) & 0x0F) << 2) | ((*(data +
+                        2) & 0xC0) >> 6)];
+        *out++ = base64table[(*(data + 2)) & 0x3F];
+        break;
+      case 2:
+        *out++ = base64table[((*(data + 1) & 0x0F) << 2)];
+        *out++ = '=';
+        break;
+      case 1:
+        *out++ = '=';
+        *out++ = '=';
+        break;
+    }
+    data += chunk;
+    len -= chunk;
+  }
+  *out = 0;
+
+  return result;
+}
diff --git a/gst-libs/gst/rtsp/gstrtspbase64.h b/gst-libs/gst/rtsp/gstrtspbase64.h
new file mode 100644 (file)
index 0000000..24183b0
--- /dev/null
@@ -0,0 +1,31 @@
+/* GStreamer
+ * Copyright (C) <2007> Mike Smith <msmith@xiph.org>
+ *
+ * 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.
+ */
+
+#ifndef __BASE64_H__
+#define __BASE64_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+gchar *gst_rtsp_base64_encode(gchar *data, gint len);
+
+G_END_DECLS
+
+#endif
diff --git a/gst-libs/gst/rtsp/gstrtspconnection.c b/gst-libs/gst/rtsp/gstrtspconnection.c
new file mode 100644 (file)
index 0000000..629932b
--- /dev/null
@@ -0,0 +1,1132 @@
+/* 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.
+ */
+
+#ifdef HAVE_CONFIG_H
+#  include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <fcntl.h>
+#include <time.h>
+
+
+/* we include this here to get the G_OS_* defines */
+#include <glib.h>
+
+#ifdef G_OS_WIN32
+#include <winsock2.h>
+#define EINPROGRESS WSAEINPROGRESS
+#else
+#include <sys/ioctl.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#endif
+
+#ifdef HAVE_FIONREAD_IN_SYS_FILIO
+#include <sys/filio.h>
+#endif
+
+#include "gstrtspconnection.h"
+#include "gstrtspbase64.h"
+
+/* the select call is also performed on the control sockets, that way
+ * we can send special commands to unlock or restart the select call */
+#define CONTROL_RESTART        'R'      /* restart the select call */
+#define CONTROL_STOP           'S'      /* stop the select call */
+#define CONTROL_SOCKETS(conn)  conn->control_sock
+#define WRITE_SOCKET(conn)     conn->control_sock[1]
+#define READ_SOCKET(conn)      conn->control_sock[0]
+
+#define SEND_COMMAND(conn, command)              \
+G_STMT_START {                                  \
+  unsigned char c; c = command;                 \
+  write (WRITE_SOCKET(conn), &c, 1);             \
+} G_STMT_END
+
+#define READ_COMMAND(conn, command, res)         \
+G_STMT_START {                                  \
+  res = read(READ_SOCKET(conn), &command, 1);    \
+} G_STMT_END
+
+#ifdef G_OS_WIN32
+#define IOCTL_SOCKET ioctlsocket
+#define CLOSE_SOCKET(sock) closesocket(sock);
+#else
+#define IOCTL_SOCKET ioctl
+#define CLOSE_SOCKET(sock) close(sock);
+#endif
+
+#ifdef G_OS_WIN32
+static int
+inet_aton (const char *c, struct in_addr *paddr)
+{
+  /* note that inet_addr is deprecated on unix because
+   * inet_addr returns -1 (INADDR_NONE) for the valid 255.255.255.255
+   * address. */
+  paddr->s_addr = inet_addr (c);
+
+  if (paddr->s_addr == INADDR_NONE)
+    return 0;
+
+  return 1;
+}
+#endif
+
+GstRTSPResult
+gst_rtsp_connection_create (GstRTSPUrl * url, GstRTSPConnection ** conn)
+{
+  gint ret;
+  GstRTSPConnection *newconn;
+
+#ifdef G_OS_WIN32
+  unsigned long flags;
+#endif /* G_OS_WIN32 */
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+  newconn = g_new0 (GstRTSPConnection, 1);
+
+#ifdef G_OS_WIN32
+  /* This should work on UNIX too. PF_UNIX sockets replaced with pipe */
+  /* pipe( CONTROL_SOCKETS(newconn) ) */
+  if ((ret = pipe (CONTROL_SOCKETS (newconn))) < 0)
+    goto no_socket_pair;
+
+  ioctlsocket (READ_SOCKET (newconn), FIONBIO, &flags);
+  ioctlsocket (WRITE_SOCKET (newconn), FIONBIO, &flags);
+#else
+  if ((ret =
+          socketpair (PF_UNIX, SOCK_STREAM, 0, CONTROL_SOCKETS (newconn))) < 0)
+    goto no_socket_pair;
+
+  fcntl (READ_SOCKET (newconn), F_SETFL, O_NONBLOCK);
+  fcntl (WRITE_SOCKET (newconn), F_SETFL, O_NONBLOCK);
+#endif
+
+  newconn->url = url;
+  newconn->fd = -1;
+  newconn->timer = g_timer_new ();
+
+  newconn->auth_method = GST_RTSP_AUTH_NONE;
+  newconn->username = NULL;
+  newconn->passwd = NULL;
+
+  *conn = newconn;
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+no_socket_pair:
+  {
+    g_free (newconn);
+    return GST_RTSP_ESYS;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_connect (GstRTSPConnection * conn, GTimeVal * timeout)
+{
+  gint fd;
+  struct sockaddr_in sa_in;
+  struct hostent *hostinfo;
+  char **addrs;
+  const gchar *ip;
+  gchar ipbuf[INET_ADDRSTRLEN];
+  struct in_addr addr;
+  gint ret;
+  guint16 port;
+  GstRTSPUrl *url;
+  fd_set writefds;
+  fd_set readfds;
+  struct timeval tv, *tvp;
+  gint max_fd, retval;
+
+#ifdef G_OS_WIN32
+  unsigned long flags;
+#endif /* G_OS_WIN32 */
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (conn->url != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (conn->fd < 0, GST_RTSP_EINVAL);
+
+  url = conn->url;
+
+  /* first check if it already is an IP address */
+  if (inet_aton (url->host, &addr)) {
+    ip = url->host;
+  } else {
+    hostinfo = gethostbyname (url->host);
+    if (!hostinfo)
+      goto not_resolved;        /* h_errno set */
+
+    if (hostinfo->h_addrtype != AF_INET)
+      goto not_ip;              /* host not an IP host */
+
+    addrs = hostinfo->h_addr_list;
+    ip = inet_ntop (AF_INET, (struct in_addr *) addrs[0], ipbuf,
+        sizeof (ipbuf));
+  }
+
+  /* get the port from the url */
+  gst_rtsp_url_get_port (url, &port);
+
+  memset (&sa_in, 0, sizeof (sa_in));
+  sa_in.sin_family = AF_INET;   /* network socket */
+  sa_in.sin_port = htons (port);        /* on port */
+  sa_in.sin_addr.s_addr = inet_addr (ip);       /* on host ip */
+
+  fd = socket (AF_INET, SOCK_STREAM, 0);
+  if (fd == -1)
+    goto sys_error;
+
+  /* set to non-blocking mode so that we can cancel the connect */
+#ifndef G_OS_WIN32
+  fcntl (fd, F_SETFL, O_NONBLOCK);
+#else
+  ioctlsocket (fd, FIONBIO, &flags);
+#endif /* G_OS_WIN32 */
+
+  /* we are going to connect ASYNC now */
+  ret = connect (fd, (struct sockaddr *) &sa_in, sizeof (sa_in));
+  if (ret == 0)
+    goto done;
+  if (errno != EINPROGRESS)
+    goto sys_error;
+
+  /* wait for connect to complete up to the specified timeout or until we got
+   * interrupted. */
+  FD_ZERO (&writefds);
+  FD_SET (fd, &writefds);
+  FD_ZERO (&readfds);
+  FD_SET (READ_SOCKET (conn), &readfds);
+
+  if (timeout->tv_sec != 0 || timeout->tv_usec != 0) {
+    tv.tv_sec = timeout->tv_sec;
+    tv.tv_usec = timeout->tv_usec;
+    tvp = &tv;
+  } else {
+    tvp = NULL;
+  }
+
+  max_fd = MAX (fd, READ_SOCKET (conn));
+
+  do {
+    retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
+  } while ((retval == -1 && errno == EINTR));
+
+  if (retval == 0)
+    goto timeout;
+  else if (retval == -1)
+    goto sys_error;
+
+done:
+  conn->fd = fd;
+  conn->ip = g_strdup (ip);
+
+  return GST_RTSP_OK;
+
+sys_error:
+  {
+    if (fd != -1)
+      CLOSE_SOCKET (fd);
+    return GST_RTSP_ESYS;
+  }
+not_resolved:
+  {
+    return GST_RTSP_ENET;
+  }
+not_ip:
+  {
+    return GST_RTSP_ENOTIP;
+  }
+timeout:
+  {
+    return GST_RTSP_ETIMEOUT;
+  }
+}
+
+static void
+add_auth_header (GstRTSPConnection * conn, GstRTSPMessage * message)
+{
+  switch (conn->auth_method) {
+    case GST_RTSP_AUTH_BASIC:{
+      gchar *user_pass =
+          g_strdup_printf ("%s:%s", conn->username, conn->passwd);
+      gchar *user_pass64 =
+          gst_rtsp_base64_encode (user_pass, strlen (user_pass));
+      gchar *auth_string = g_strdup_printf ("Basic %s", user_pass64);
+
+      gst_rtsp_message_add_header (message, GST_RTSP_HDR_AUTHORIZATION,
+          auth_string);
+
+      g_free (user_pass);
+      g_free (user_pass64);
+      g_free (auth_string);
+      break;
+    }
+    default:
+      /* Nothing to do */
+      break;
+  }
+}
+
+static void
+add_date_header (GstRTSPMessage * message)
+{
+  GTimeVal tv;
+  gchar date_string[100];
+
+  g_get_current_time (&tv);
+  strftime (date_string, sizeof (date_string), "%a, %d %b %Y %H:%M:%S GMT",
+      gmtime (&tv.tv_sec));
+
+  gst_rtsp_message_add_header (message, GST_RTSP_HDR_DATE, date_string);
+}
+
+GstRTSPResult
+gst_rtsp_connection_write (GstRTSPConnection * conn, const guint8 * data,
+    guint size, GTimeVal * timeout)
+{
+  guint towrite;
+  fd_set writefds;
+  fd_set readfds;
+  int max_fd;
+  gint retval;
+  struct timeval tv, *tvp;
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
+
+  FD_ZERO (&writefds);
+  FD_SET (conn->fd, &writefds);
+  FD_ZERO (&readfds);
+  FD_SET (READ_SOCKET (conn), &readfds);
+
+  max_fd = MAX (conn->fd, READ_SOCKET (conn));
+
+  if (timeout) {
+    tv.tv_sec = timeout->tv_sec;
+    tv.tv_usec = timeout->tv_usec;
+    tvp = &tv;
+  } else {
+    tvp = NULL;
+  }
+
+  towrite = size;
+
+  while (towrite > 0) {
+    gint written;
+
+    do {
+      retval = select (max_fd + 1, &readfds, &writefds, NULL, tvp);
+    } while ((retval == -1 && errno == EINTR));
+
+    if (retval == 0)
+      goto timeout;
+
+    if (retval == -1)
+      goto select_error;
+
+    if (FD_ISSET (READ_SOCKET (conn), &readfds)) {
+      /* read all stop commands */
+      while (TRUE) {
+        gchar command;
+        int res;
+
+        READ_COMMAND (conn, command, res);
+        if (res <= 0) {
+          /* no more commands */
+          break;
+        }
+      }
+      goto stopped;
+    }
+
+    /* now we can write */
+    written = write (conn->fd, data, towrite);
+    if (written < 0) {
+      if (errno != EAGAIN && errno != EINTR)
+        goto write_error;
+    } else {
+      towrite -= written;
+      data += written;
+    }
+  }
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+timeout:
+  {
+    return GST_RTSP_ETIMEOUT;
+  }
+select_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+stopped:
+  {
+    return GST_RTSP_EINTR;
+  }
+write_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_send (GstRTSPConnection * conn, GstRTSPMessage * message,
+    GTimeVal * timeout)
+{
+  GString *str = NULL;
+  GstRTSPResult res;
+
+#ifdef G_OS_WIN32
+  WSADATA w;
+  int error;
+#endif
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (message != NULL, GST_RTSP_EINVAL);
+
+#ifdef G_OS_WIN32
+  error = WSAStartup (0x0202, &w);
+
+  if (error)
+    goto startup_error;
+
+  if (w.wVersion != 0x0202)
+    goto version_error;
+#endif
+
+  str = g_string_new ("");
+
+  switch (message->type) {
+    case GST_RTSP_MESSAGE_REQUEST:
+      /* create request string, add CSeq */
+      g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
+          "CSeq: %d\r\n",
+          gst_rtsp_method_as_text (message->type_data.request.method),
+          message->type_data.request.uri, conn->cseq++);
+      /* add session id if we have one */
+      if (conn->session_id[0] != '\0') {
+        gst_rtsp_message_add_header (message, GST_RTSP_HDR_SESSION,
+            conn->session_id);
+      }
+      /* add any authentication headers */
+      add_auth_header (conn, message);
+      break;
+    case GST_RTSP_MESSAGE_RESPONSE:
+      /* create response string */
+      g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
+          message->type_data.response.code, message->type_data.response.reason);
+      break;
+    case GST_RTSP_MESSAGE_DATA:
+    {
+      guint8 data_header[4];
+
+      /* prepare data header */
+      data_header[0] = '$';
+      data_header[1] = message->type_data.data.channel;
+      data_header[2] = (message->body_size >> 8) & 0xff;
+      data_header[3] = message->body_size & 0xff;
+
+      /* create string with header and data */
+      str = g_string_append_len (str, (gchar *) data_header, 4);
+      str =
+          g_string_append_len (str, (gchar *) message->body,
+          message->body_size);
+      break;
+    }
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  /* append headers and body */
+  if (message->type != GST_RTSP_MESSAGE_DATA) {
+    /* add date header */
+    add_date_header (message);
+
+    /* append headers */
+    gst_rtsp_message_append_headers (message, str);
+
+    /* append Content-Length and body if needed */
+    if (message->body != NULL && message->body_size > 0) {
+      gchar *len;
+
+      len = g_strdup_printf ("%d", message->body_size);
+      g_string_append_printf (str, "%s: %s\r\n",
+          gst_rtsp_header_as_text (GST_RTSP_HDR_CONTENT_LENGTH), len);
+      g_free (len);
+      /* header ends here */
+      g_string_append (str, "\r\n");
+      str =
+          g_string_append_len (str, (gchar *) message->body,
+          message->body_size);
+    } else {
+      /* just end headers */
+      g_string_append (str, "\r\n");
+    }
+  }
+
+  /* write request */
+  res =
+      gst_rtsp_connection_write (conn, (guint8 *) str->str, str->len, timeout);
+
+  g_string_free (str, TRUE);
+
+  return res;
+
+#ifdef G_OS_WIN32
+startup_error:
+  {
+    g_warning ("Error %d on WSAStartup", error);
+    return GST_RTSP_EWSASTART;
+  }
+version_error:
+  {
+    g_warning ("Windows sockets are not version 0x202 (current 0x%x)",
+        w.wVersion);
+    WSACleanup ();
+    return GST_RTSP_EWSAVERSION;
+  }
+#endif
+}
+
+static GstRTSPResult
+read_line (gint fd, gchar * buffer, guint size)
+{
+  guint idx;
+  gchar c;
+  gint r;
+
+  idx = 0;
+  while (TRUE) {
+    r = read (fd, &c, 1);
+    if (r == 0) {
+      goto eof;
+    } else if (r < 0) {
+      if (errno != EAGAIN && errno != EINTR)
+        goto read_error;
+    } else {
+      if (c == '\n')            /* end on \n */
+        break;
+      if (c == '\r')            /* ignore \r */
+        continue;
+
+      if (idx < size - 1)
+        buffer[idx++] = c;
+    }
+  }
+  buffer[idx] = '\0';
+
+  return GST_RTSP_OK;
+
+eof:
+  {
+    return GST_RTSP_EEOF;
+  }
+read_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+}
+
+static void
+read_string (gchar * dest, gint size, gchar ** src)
+{
+  gint idx;
+
+  idx = 0;
+  /* skip spaces */
+  while (g_ascii_isspace (**src))
+    (*src)++;
+
+  while (!g_ascii_isspace (**src) && **src != '\0') {
+    if (idx < size - 1)
+      dest[idx++] = **src;
+    (*src)++;
+  }
+  if (size > 0)
+    dest[idx] = '\0';
+}
+
+static void
+read_key (gchar * dest, gint size, gchar ** src)
+{
+  gint idx;
+
+  idx = 0;
+  while (**src != ':' && **src != '\0') {
+    if (idx < size - 1)
+      dest[idx++] = **src;
+    (*src)++;
+  }
+  if (size > 0)
+    dest[idx] = '\0';
+}
+
+static GstRTSPResult
+parse_response_status (gchar * buffer, GstRTSPMessage * msg)
+{
+  GstRTSPResult res;
+  gchar versionstr[20];
+  gchar codestr[4];
+  gint code;
+  gchar *bptr;
+
+  bptr = buffer;
+
+  read_string (versionstr, sizeof (versionstr), &bptr);
+  read_string (codestr, sizeof (codestr), &bptr);
+  code = atoi (codestr);
+
+  while (g_ascii_isspace (*bptr))
+    bptr++;
+
+  if (strcmp (versionstr, "RTSP/1.0") == 0)
+    GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
+        parse_error);
+  else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+    GST_RTSP_CHECK (gst_rtsp_message_init_response (msg, code, bptr, NULL),
+        parse_error);
+    msg->type_data.response.version = GST_RTSP_VERSION_INVALID;
+  } else
+    goto parse_error;
+
+  return GST_RTSP_OK;
+
+parse_error:
+  {
+    return GST_RTSP_EPARSE;
+  }
+}
+
+static GstRTSPResult
+parse_request_line (gchar * buffer, GstRTSPMessage * msg)
+{
+  GstRTSPResult res = GST_RTSP_OK;
+  gchar versionstr[20];
+  gchar methodstr[20];
+  gchar urlstr[4096];
+  gchar *bptr;
+  GstRTSPMethod method;
+
+  bptr = buffer;
+
+  read_string (methodstr, sizeof (methodstr), &bptr);
+  method = gst_rtsp_find_method (methodstr);
+
+  read_string (urlstr, sizeof (urlstr), &bptr);
+  if (*urlstr == '\0')
+    res = GST_RTSP_EPARSE;
+
+  read_string (versionstr, sizeof (versionstr), &bptr);
+
+  if (*bptr != '\0')
+    res = GST_RTSP_EPARSE;
+
+  if (strcmp (versionstr, "RTSP/1.0") == 0) {
+    if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
+      res = GST_RTSP_EPARSE;
+  } else if (strncmp (versionstr, "RTSP/", 5) == 0) {
+    if (gst_rtsp_message_init_request (msg, method, urlstr) != GST_RTSP_OK)
+      res = GST_RTSP_EPARSE;
+    msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
+  } else {
+    gst_rtsp_message_init_request (msg, method, urlstr);
+    msg->type_data.request.version = GST_RTSP_VERSION_INVALID;
+    res = GST_RTSP_EPARSE;
+  }
+
+  return res;
+}
+
+/* parsing lines means reading a Key: Value pair */
+static GstRTSPResult
+parse_line (gchar * buffer, GstRTSPMessage * msg)
+{
+  gchar key[32];
+  gchar *bptr;
+  GstRTSPHeaderField field;
+
+  bptr = buffer;
+
+  /* read key */
+  read_key (key, sizeof (key), &bptr);
+  if (*bptr != ':')
+    goto no_column;
+
+  bptr++;
+
+  field = gst_rtsp_find_header_field (key);
+  if (field != GST_RTSP_HDR_INVALID) {
+    while (g_ascii_isspace (*bptr))
+      bptr++;
+    gst_rtsp_message_add_header (msg, field, bptr);
+  }
+
+  return GST_RTSP_OK;
+
+no_column:
+  {
+    return GST_RTSP_EPARSE;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_read (GstRTSPConnection * conn, guint8 * data, guint size,
+    GTimeVal * timeout)
+{
+  fd_set readfds;
+  guint toread;
+  gint retval;
+  struct timeval tv_timeout, *ptv_timeout = NULL;
+
+#ifndef G_OS_WIN32
+  gint avail;
+#else
+  gulong avail;
+#endif
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+
+  if (size == 0)
+    return GST_RTSP_OK;
+
+  toread = size;
+
+  /* if the call fails, just go in the select.. it should not fail. Else if
+   * there is enough data to read, skip the select call al together.*/
+  if (IOCTL_SOCKET (conn->fd, FIONREAD, &avail) < 0)
+    avail = 0;
+  else if (avail >= toread)
+    goto do_read;
+
+  /* configure timeout if any */
+  if (timeout != NULL) {
+    tv_timeout.tv_sec = timeout->tv_sec;
+    tv_timeout.tv_usec = timeout->tv_usec;
+    ptv_timeout = &tv_timeout;
+  }
+
+  FD_ZERO (&readfds);
+  FD_SET (conn->fd, &readfds);
+  FD_SET (READ_SOCKET (conn), &readfds);
+
+  while (toread > 0) {
+    gint bytes;
+
+    do {
+      retval = select (FD_SETSIZE, &readfds, NULL, NULL, ptv_timeout);
+    } while ((retval == -1 && errno == EINTR));
+
+    if (retval == -1)
+      goto select_error;
+
+    /* check for timeout */
+    if (retval == 0)
+      goto select_timeout;
+
+    if (FD_ISSET (READ_SOCKET (conn), &readfds)) {
+      /* read all stop commands */
+      while (TRUE) {
+        gchar command;
+        int res;
+
+        READ_COMMAND (conn, command, res);
+        if (res <= 0) {
+          /* no more commands */
+          break;
+        }
+      }
+      goto stopped;
+    }
+
+  do_read:
+    /* if we get here there is activity on the real fd since the select
+     * completed and the control socket was not readable. */
+    bytes = read (conn->fd, data, toread);
+
+    if (bytes == 0) {
+      goto eof;
+    } else if (bytes < 0) {
+      if (errno != EAGAIN && errno != EINTR)
+        goto read_error;
+    } else {
+      toread -= bytes;
+      data += bytes;
+    }
+  }
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+select_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+select_timeout:
+  {
+    return GST_RTSP_ETIMEOUT;
+  }
+stopped:
+  {
+    return GST_RTSP_EINTR;
+  }
+eof:
+  {
+    return GST_RTSP_EEOF;
+  }
+read_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+}
+
+static GstRTSPResult
+read_body (GstRTSPConnection * conn, glong content_length, GstRTSPMessage * msg,
+    GTimeVal * timeout)
+{
+  guint8 *body;
+  GstRTSPResult res;
+
+  if (content_length <= 0) {
+    body = NULL;
+    content_length = 0;
+    goto done;
+  }
+
+  body = g_malloc (content_length + 1);
+  body[content_length] = '\0';
+
+  GST_RTSP_CHECK (gst_rtsp_connection_read (conn, body, content_length,
+          timeout), read_error);
+
+  content_length += 1;
+
+done:
+  gst_rtsp_message_take_body (msg, (guint8 *) body, content_length);
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+read_error:
+  {
+    g_free (body);
+    return res;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_receive (GstRTSPConnection * conn, GstRTSPMessage * msg,
+    GTimeVal * timeout)
+{
+  gchar buffer[4096];
+  gint line;
+  glong content_length;
+  GstRTSPResult res;
+  gboolean need_body;
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  line = 0;
+
+  need_body = TRUE;
+
+  res = GST_RTSP_OK;
+  /* parse first line and headers */
+  while (res == GST_RTSP_OK) {
+    guint8 c;
+
+    /* read first character, this identifies data messages */
+    GST_RTSP_CHECK (gst_rtsp_connection_read (conn, &c, 1, timeout),
+        read_error);
+
+    /* check for data packet, first character is $ */
+    if (c == '$') {
+      guint16 size;
+
+      /* data packets are $<1 byte channel><2 bytes length,BE><data bytes> */
+
+      /* read channel, which is the next char */
+      GST_RTSP_CHECK (gst_rtsp_connection_read (conn, &c, 1, timeout),
+          read_error);
+
+      /* now we create a data message */
+      gst_rtsp_message_init_data (msg, c);
+
+      /* next two bytes are the length of the data */
+      GST_RTSP_CHECK (gst_rtsp_connection_read (conn, (guint8 *) & size, 2,
+              timeout), read_error);
+
+      size = GUINT16_FROM_BE (size);
+
+      /* and read the body */
+      res = read_body (conn, size, msg, timeout);
+      need_body = FALSE;
+      break;
+    } else {
+      gint offset = 0;
+
+      /* we have a regular response */
+      if (c != '\r') {
+        buffer[0] = c;
+        offset = 1;
+      }
+      /* should not happen */
+      if (c == '\n')
+        break;
+
+      /* read lines */
+      GST_RTSP_CHECK (read_line (conn->fd, buffer + offset,
+              sizeof (buffer) - offset), read_error);
+
+      if (buffer[0] == '\0')
+        break;
+
+      if (line == 0) {
+        /* first line, check for response status */
+        if (g_str_has_prefix (buffer, "RTSP")) {
+          res = parse_response_status (buffer, msg);
+        } else {
+          res = parse_request_line (buffer, msg);
+        }
+      } else {
+        /* else just parse the line */
+        parse_line (buffer, msg);
+      }
+    }
+    line++;
+  }
+
+  /* read the rest of the body if needed */
+  if (need_body) {
+    gchar *session_id;
+    gchar *hdrval;
+
+    /* see if there is a Content-Length header */
+    if (gst_rtsp_message_get_header (msg, GST_RTSP_HDR_CONTENT_LENGTH,
+            &hdrval, 0) == GST_RTSP_OK) {
+      /* there is, read the body */
+      content_length = atol (hdrval);
+      GST_RTSP_CHECK (read_body (conn, content_length, msg, timeout),
+          read_error);
+    }
+
+    /* save session id in the connection for further use */
+    if (gst_rtsp_message_get_header (msg, GST_RTSP_HDR_SESSION,
+            &session_id, 0) == GST_RTSP_OK) {
+      gint maxlen, i;
+
+      /* default session timeout */
+      conn->timeout = 60;
+
+      maxlen = sizeof (conn->session_id) - 1;
+      /* the sessionid can have attributes marked with ;
+       * Make sure we strip them */
+      for (i = 0; session_id[i] != '\0'; i++) {
+        if (session_id[i] == ';') {
+          maxlen = i;
+          /* parse timeout */
+          do {
+            i++;
+          } while (g_ascii_isspace (session_id[i]));
+          if (g_str_has_prefix (&session_id[i], "timeout=")) {
+            gint to;
+
+            /* if we parsed something valid, configure */
+            if ((to = atoi (&session_id[i + 9])) > 0)
+              conn->timeout = to;
+          }
+          break;
+        }
+      }
+
+      /* make sure to not overflow */
+      strncpy (conn->session_id, session_id, maxlen);
+      conn->session_id[maxlen] = '\0';
+    }
+  }
+  return res;
+
+read_error:
+  {
+    return res;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_close (GstRTSPConnection * conn)
+{
+  gint res;
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+  g_free (conn->ip);
+  conn->ip = NULL;
+
+  if (conn->fd != -1) {
+    res = CLOSE_SOCKET (conn->fd);
+#ifdef G_OS_WIN32
+    WSACleanup ();
+#endif
+    conn->fd = -1;
+    if (res != 0)
+      goto sys_error;
+  }
+
+  return GST_RTSP_OK;
+
+sys_error:
+  {
+    return GST_RTSP_ESYS;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_connection_free (GstRTSPConnection * conn)
+{
+  GstRTSPResult res;
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+#ifdef G_OS_WIN32
+  WSACleanup ();
+#endif
+  res = gst_rtsp_connection_close (conn);
+  g_timer_destroy (conn->timer);
+  g_free (conn->username);
+  g_free (conn->passwd);
+  g_free (conn);
+
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_connection_next_timeout (GstRTSPConnection * conn, GTimeVal * timeout)
+{
+  gdouble elapsed;
+  glong sec;
+  gulong usec;
+
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (timeout != NULL, GST_RTSP_EINVAL);
+
+  elapsed = g_timer_elapsed (conn->timer, &usec);
+  if (elapsed >= conn->timeout) {
+    sec = 0;
+    usec = 0;
+  } else {
+    sec = conn->timeout - elapsed;
+  }
+
+  timeout->tv_sec = sec;
+  timeout->tv_usec = usec;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_reset_timeout (GstRTSPConnection * conn)
+{
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+  g_timer_start (conn->timer);
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_flush (GstRTSPConnection * conn, gboolean flush)
+{
+  g_return_val_if_fail (conn != NULL, GST_RTSP_EINVAL);
+
+  if (flush) {
+    SEND_COMMAND (conn, CONTROL_STOP);
+  } else {
+    while (TRUE) {
+      gchar command;
+      int res;
+
+      READ_COMMAND (conn, command, res);
+      if (res <= 0) {
+        /* no more commands */
+        break;
+      }
+    }
+  }
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_connection_set_auth (GstRTSPConnection * conn,
+    GstRTSPAuthMethod method, gchar * user, gchar * pass)
+{
+  /* Digest isn't implemented yet */
+  if (method == GST_RTSP_AUTH_DIGEST)
+    return GST_RTSP_ENOTIMPL;
+
+  /* Make sure the username and passwd are being set for authentication */
+  if (method == GST_RTSP_AUTH_NONE && (user == NULL || pass == NULL))
+    return GST_RTSP_EINVAL;
+
+  /* ":" chars are not allowed in usernames for basic auth */
+  if (method == GST_RTSP_AUTH_BASIC && g_strrstr (user, ":") != NULL)
+    return GST_RTSP_EINVAL;
+
+  g_free (conn->username);
+  g_free (conn->passwd);
+
+  conn->auth_method = method;
+  conn->username = g_strdup (user);
+  conn->passwd = g_strdup (pass);
+
+  return GST_RTSP_OK;
+}
diff --git a/gst-libs/gst/rtsp/gstrtspconnection.h b/gst-libs/gst/rtsp/gstrtspconnection.h
new file mode 100644 (file)
index 0000000..7702b2e
--- /dev/null
@@ -0,0 +1,105 @@
+/* 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_RTSP_CONNECTION_H__
+#define __GST_RTSP_CONNECTION_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+#include <gst/rtsp/gstrtspurl.h>
+#include <gst/rtsp/gstrtspmessage.h>
+
+G_BEGIN_DECLS
+
+typedef struct _GstRTSPConnection
+{
+  /* URL for the connection */
+  GstRTSPUrl *url;
+
+  /* connection state */
+  gint   fd;
+  gint   control_sock[2];
+  gchar *ip;
+
+  /* Session state */
+  gint          cseq;                   /* sequence number */
+  gchar         session_id[512];        /* session id */
+  gint          timeout;                /* session timeout in seconds */
+  GTimer       *timer;                  /* timeout timer */
+
+  /* Authentication */
+  GstRTSPAuthMethod  auth_method;
+  gchar             *username;
+  gchar             *passwd;
+} GstRTSPConnection;
+
+/* opening/closing a connection */
+GstRTSPResult      gst_rtsp_connection_create   (GstRTSPUrl *url, GstRTSPConnection **conn);
+GstRTSPResult      gst_rtsp_connection_connect  (GstRTSPConnection *conn, GTimeVal *timeout);
+GstRTSPResult      gst_rtsp_connection_close    (GstRTSPConnection *conn);
+GstRTSPResult      gst_rtsp_connection_free     (GstRTSPConnection *conn);
+
+/* sending/receiving raw bytes */
+GstRTSPResult      gst_rtsp_connection_read     (GstRTSPConnection * conn, guint8 * data,
+                                                 guint size, GTimeVal * timeout);
+GstRTSPResult      gst_rtsp_connection_write    (GstRTSPConnection * conn, const guint8 * data, 
+                                                guint size, GTimeVal * timeout);
+
+/* sending/receiving messages */
+GstRTSPResult      gst_rtsp_connection_send     (GstRTSPConnection *conn, GstRTSPMessage *message, GTimeVal *timeout);
+GstRTSPResult      gst_rtsp_connection_receive  (GstRTSPConnection *conn, GstRTSPMessage *message, GTimeVal *timeout);
+
+/* reset the timeout */
+GstRTSPResult      gst_rtsp_connection_next_timeout   (GstRTSPConnection *conn, GTimeVal *timeout);
+GstRTSPResult      gst_rtsp_connection_reset_timeout  (GstRTSPConnection *conn);
+
+/* flushing state */
+GstRTSPResult      gst_rtsp_connection_flush    (GstRTSPConnection *conn, gboolean flush);
+
+/* Configure Authentication data */
+GstRTSPResult      gst_rtsp_connection_set_auth (GstRTSPConnection *conn, GstRTSPAuthMethod method,
+                                                 gchar *user, gchar *pass);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_CONNECTION_H__ */
diff --git a/gst-libs/gst/rtsp/gstrtspdefs.c b/gst-libs/gst/rtsp/gstrtspdefs.c
new file mode 100644 (file)
index 0000000..921692a
--- /dev/null
@@ -0,0 +1,316 @@
+/* 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.
+ */
+
+#include <errno.h>
+
+extern int h_errno;
+
+#include "gstrtspdefs.h"
+
+#ifndef G_OS_WIN32
+#include <netdb.h>
+#endif
+
+static const gchar *rtsp_results[] = {
+  "OK",
+  /* errors */
+  "Generic error",
+  "Invalid parameter specified",
+  "Operation interrupted",
+  "Out of memory",
+  "Cannot resolve host",
+  "Function not implemented",
+  "System error: %s",
+  "Parse error",
+  "Error on WSAStartup",
+  "Windows sockets are not version 0x202",
+  "Received end-of-file",
+  "Network error: %s",
+  "Host is not a valid IP address",
+  "Timeout while waiting for server response",
+  "Unknown error (%d)",
+  NULL
+};
+
+static const gchar *rtsp_methods[] = {
+  "DESCRIBE",
+  "ANNOUNCE",
+  "GET_PARAMETER",
+  "OPTIONS",
+  "PAUSE",
+  "PLAY",
+  "RECORD",
+  "REDIRECT",
+  "SETUP",
+  "SET_PARAMETER",
+  "TEARDOWN",
+  NULL
+};
+
+static const gchar *rtsp_headers[] = {
+  "Accept",                     /* Accept               R      opt.      entity */
+  "Accept-Encoding",            /* Accept-Encoding      R      opt.      entity */
+  "Accept-Language",            /* Accept-Language      R      opt.      all */
+  "Allow",                      /* Allow                r      opt.      all */
+  "Authorization",              /* Authorization        R      opt.      all */
+  "Bandwidth",                  /* Bandwidth            R      opt.      all */
+  "Blocksize",                  /* Blocksize            R      opt.      all but OPTIONS, TEARDOWN */
+  "Cache-Control",              /* Cache-Control        g      opt.      SETUP */
+  "Conference",                 /* Conference           R      opt.      SETUP */
+  "Connection",                 /* Connection           g      req.      all */
+  "Content-Base",               /* Content-Base         e      opt.      entity */
+  "Content-Encoding",           /* Content-Encoding     e      req.      SET_PARAMETER, DESCRIBE, ANNOUNCE */
+  "Content-Language",           /* Content-Language     e      req.      DESCRIBE, ANNOUNCE */
+  "Content-Length",             /* Content-Length       e      req.      SET_PARAMETER, ANNOUNCE, entity */
+  "Content-Location",           /* Content-Location     e      opt.      entity */
+  "Content-Type",               /* Content-Type         e      req.      SET_PARAMETER, ANNOUNCE, entity */
+  "CSeq",                       /* CSeq                 g      req.      all */
+  "Date",                       /* Date                 g      opt.      all */
+  "Expires",                    /* Expires              e      opt.      DESCRIBE, ANNOUNCE */
+  "From",                       /* From                 R      opt.      all */
+  "If-Modified-Since",          /* If-Modified-Since    R      opt.      DESCRIBE, SETUP */
+  "Last-Modified",              /* Last-Modified        e      opt.      entity */
+  "Proxy-Authenticate",         /* Proxy-Authenticate */
+  "Proxy-Require",              /* Proxy-Require        R      req.      all */
+  "Public",                     /* Public               r      opt.      all */
+  "Range",                      /* Range                Rr     opt.      PLAY, PAUSE, RECORD */
+  "Referer",                    /* Referer              R      opt.      all */
+  "Require",                    /* Require              R      req.      all */
+  "Retry-After",                /* Retry-After          r      opt.      all */
+  "RTP-Info",                   /* RTP-Info             r      req.      PLAY */
+  "Scale",                      /* Scale                Rr     opt.      PLAY, RECORD */
+  "Session",                    /* Session              Rr     req.      all but SETUP, OPTIONS */
+  "Server",                     /* Server               r      opt.      all */
+  "Speed",                      /* Speed                Rr     opt.      PLAY */
+  "Transport",                  /* Transport            Rr     req.      SETUP */
+  "Unsupported",                /* Unsupported          r      req.      all */
+  "User-Agent",                 /* User-Agent           R      opt.      all */
+  "Via",                        /* Via                  g      opt.      all */
+  "WWW-Authenticate",           /* WWW-Authenticate     r      opt.      all */
+
+  /* Real extensions */
+  "ClientChallenge",            /* ClientChallenge */
+  "RealChallenge1",             /* RealChallenge1 */
+  "RealChallenge2",             /* RealChallenge2 */
+  "RealChallenge3",             /* RealChallenge3 */
+  "Subscribe",                  /* Subscribe */
+  "Alert",                      /* Alert */
+  "ClientID",                   /* ClientID */
+  "CompanyID",                  /* CompanyID */
+  "GUID",                       /* GUID */
+  "RegionData",                 /* RegionData */
+  "SupportsMaximumASMBandwidth",        /* SupportsMaximumASMBandwidth */
+  "Language",                   /* Language */
+  "PlayerStarttime",            /* PlayerStarttime */
+
+  NULL
+};
+
+#define DEF_STATUS(c, t) \
+  g_hash_table_insert (statuses, GUINT_TO_POINTER(c), t)
+
+static GHashTable *
+rtsp_init_status (void)
+{
+  GHashTable *statuses = g_hash_table_new (NULL, NULL);
+
+  DEF_STATUS (GST_RTSP_STS_CONTINUE, "Continue");
+  DEF_STATUS (GST_RTSP_STS_OK, "OK");
+  DEF_STATUS (GST_RTSP_STS_CREATED, "Created");
+  DEF_STATUS (GST_RTSP_STS_LOW_ON_STORAGE, "Low on Storage Space");
+  DEF_STATUS (GST_RTSP_STS_MULTIPLE_CHOICES, "Multiple Choices");
+  DEF_STATUS (GST_RTSP_STS_MOVED_PERMANENTLY, "Moved Permanently");
+  DEF_STATUS (GST_RTSP_STS_MOVE_TEMPORARILY, "Moved Temporarily");
+  DEF_STATUS (GST_RTSP_STS_SEE_OTHER, "See Other");
+  DEF_STATUS (GST_RTSP_STS_NOT_MODIFIED, "Not Modified");
+  DEF_STATUS (GST_RTSP_STS_USE_PROXY, "Use Proxy");
+  DEF_STATUS (GST_RTSP_STS_BAD_REQUEST, "Bad Request");
+  DEF_STATUS (GST_RTSP_STS_UNAUTHORIZED, "Unauthorized");
+  DEF_STATUS (GST_RTSP_STS_PAYMENT_REQUIRED, "Payment Required");
+  DEF_STATUS (GST_RTSP_STS_FORBIDDEN, "Forbidden");
+  DEF_STATUS (GST_RTSP_STS_NOT_FOUND, "Not Found");
+  DEF_STATUS (GST_RTSP_STS_METHOD_NOT_ALLOWED, "Method Not Allowed");
+  DEF_STATUS (GST_RTSP_STS_NOT_ACCEPTABLE, "Not Acceptable");
+  DEF_STATUS (GST_RTSP_STS_PROXY_AUTH_REQUIRED,
+      "Proxy Authentication Required");
+  DEF_STATUS (GST_RTSP_STS_REQUEST_TIMEOUT, "Request Time-out");
+  DEF_STATUS (GST_RTSP_STS_GONE, "Gone");
+  DEF_STATUS (GST_RTSP_STS_LENGTH_REQUIRED, "Length Required");
+  DEF_STATUS (GST_RTSP_STS_PRECONDITION_FAILED, "Precondition Failed");
+  DEF_STATUS (GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE,
+      "Request Entity Too Large");
+  DEF_STATUS (GST_RTSP_STS_REQUEST_URI_TOO_LARGE, "Request-URI Too Large");
+  DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
+  DEF_STATUS (GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD,
+      "Parameter Not Understood");
+  DEF_STATUS (GST_RTSP_STS_CONFERENCE_NOT_FOUND, "Conference Not Found");
+  DEF_STATUS (GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH, "Not Enough Bandwidth");
+  DEF_STATUS (GST_RTSP_STS_SESSION_NOT_FOUND, "Session Not Found");
+  DEF_STATUS (GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
+      "Method Not Valid in This State");
+  DEF_STATUS (GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE,
+      "Header Field Not Valid for Resource");
+  DEF_STATUS (GST_RTSP_STS_INVALID_RANGE, "Invalid Range");
+  DEF_STATUS (GST_RTSP_STS_PARAMETER_IS_READONLY, "Parameter Is Read-Only");
+  DEF_STATUS (GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED,
+      "Aggregate operation not allowed");
+  DEF_STATUS (GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED,
+      "Only aggregate operation allowed");
+  DEF_STATUS (GST_RTSP_STS_UNSUPPORTED_TRANSPORT, "Unsupported transport");
+  DEF_STATUS (GST_RTSP_STS_DESTINATION_UNREACHABLE, "Destination unreachable");
+  DEF_STATUS (GST_RTSP_STS_INTERNAL_SERVER_ERROR, "Internal Server Error");
+  DEF_STATUS (GST_RTSP_STS_NOT_IMPLEMENTED, "Not Implemented");
+  DEF_STATUS (GST_RTSP_STS_BAD_GATEWAY, "Bad Gateway");
+  DEF_STATUS (GST_RTSP_STS_SERVICE_UNAVAILABLE, "Service Unavailable");
+  DEF_STATUS (GST_RTSP_STS_GATEWAY_TIMEOUT, "Gateway Time-out");
+  DEF_STATUS (GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
+      "RTSP Version not supported");
+  DEF_STATUS (GST_RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
+
+  return statuses;
+}
+
+gchar *
+gst_rtsp_strresult (GstRTSPResult result)
+{
+  gint idx;
+  gchar *res;
+
+  idx = ABS (result);
+  idx = CLAMP (idx, 0, -GST_RTSP_ELAST);
+
+  switch (idx) {
+    case -GST_RTSP_ESYS:
+      res = g_strdup_printf (rtsp_results[idx], g_strerror (errno));
+      break;
+    case -GST_RTSP_ENET:
+#ifndef G_OS_WIN32
+      res = g_strdup_printf (rtsp_results[idx], hstrerror (h_errno));
+#else
+      res =
+          g_strdup
+          ("not supported on win32, implement me in a different way ??");
+#endif
+      break;
+    case -GST_RTSP_ELAST:
+      res = g_strdup_printf (rtsp_results[idx], result);
+      break;
+    default:
+      res = g_strdup (rtsp_results[idx]);
+      break;
+  }
+  return res;
+}
+
+const gchar *
+gst_rtsp_method_as_text (GstRTSPMethod method)
+{
+  gint i;
+
+  if (method == GST_RTSP_INVALID)
+    return NULL;
+
+  i = 0;
+  while ((method & 1) == 0) {
+    i++;
+    method >>= 1;
+  }
+  return rtsp_methods[i];
+}
+
+const gchar *
+gst_rtsp_version_as_text (GstRTSPVersion version)
+{
+  switch (version) {
+    case GST_RTSP_VERSION_1_0:
+      return "1.0";
+
+    default:
+      return "0.0";
+  }
+}
+
+const gchar *
+gst_rtsp_header_as_text (GstRTSPHeaderField field)
+{
+  if (field == GST_RTSP_HDR_INVALID)
+    return NULL;
+  else
+    return rtsp_headers[field - 1];
+}
+
+const gchar *
+gst_rtsp_status_as_text (GstRTSPStatusCode code)
+{
+  static GHashTable *statuses;
+
+  if (G_UNLIKELY (statuses == NULL))
+    statuses = rtsp_init_status ();
+
+  return g_hash_table_lookup (statuses, GUINT_TO_POINTER (code));
+}
+
+GstRTSPHeaderField
+gst_rtsp_find_header_field (const gchar * header)
+{
+  gint idx;
+
+  for (idx = 0; rtsp_headers[idx]; idx++) {
+    if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) {
+      return idx + 1;
+    }
+  }
+  return GST_RTSP_HDR_INVALID;
+}
+
+GstRTSPMethod
+gst_rtsp_find_method (const gchar * method)
+{
+  gint idx;
+
+  for (idx = 0; rtsp_methods[idx]; idx++) {
+    if (g_ascii_strcasecmp (rtsp_methods[idx], method) == 0) {
+      return (1 << idx);
+    }
+  }
+  return GST_RTSP_INVALID;
+}
diff --git a/gst-libs/gst/rtsp/gstrtspdefs.h b/gst-libs/gst/rtsp/gstrtspdefs.h
new file mode 100644 (file)
index 0000000..28a1c06
--- /dev/null
@@ -0,0 +1,249 @@
+/* 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_RTSP_DEFS_H__
+#define __GST_RTSP_DEFS_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+#define GST_RTSP_CHECK(stmt, label)  \
+G_STMT_START { \
+  if (G_UNLIKELY ((res = (stmt)) != GST_RTSP_OK)) \
+    goto label; \
+} G_STMT_END
+
+typedef enum {
+  GST_RTSP_OK          =  0,
+  /* errors */
+  GST_RTSP_ERROR       = -1,
+  GST_RTSP_EINVAL      = -2,
+  GST_RTSP_EINTR       = -3,
+  GST_RTSP_ENOMEM      = -4,
+  GST_RTSP_ERESOLV     = -5,
+  GST_RTSP_ENOTIMPL    = -6,
+  GST_RTSP_ESYS        = -7,
+  GST_RTSP_EPARSE      = -8,
+  GST_RTSP_EWSASTART   = -9,
+  GST_RTSP_EWSAVERSION = -10,
+  GST_RTSP_EEOF        = -11,
+  GST_RTSP_ENET        = -12,
+  GST_RTSP_ENOTIP      = -13,
+  GST_RTSP_ETIMEOUT    = -14,
+
+  GST_RTSP_ELAST       = -15,
+} GstRTSPResult;
+
+typedef enum {
+  GST_RTSP_FAM_NONE,
+  GST_RTSP_FAM_INET,
+  GST_RTSP_FAM_INET6,
+} GstRTSPFamily;
+
+typedef enum {
+  GST_RTSP_STATE_INVALID,
+  GST_RTSP_STATE_INIT,
+  GST_RTSP_STATE_READY,
+  GST_RTSP_STATE_SEEKING,
+  GST_RTSP_STATE_PLAYING,
+  GST_RTSP_STATE_RECORDING,
+} GstRTSPState;
+
+typedef enum {
+  GST_RTSP_VERSION_INVALID = 0x00,
+  GST_RTSP_VERSION_1_0     = 0x10,
+} GstRTSPVersion;
+
+typedef enum {
+  GST_RTSP_INVALID          = 0,
+  GST_RTSP_DESCRIBE         = (1 <<  0),
+  GST_RTSP_ANNOUNCE         = (1 <<  1),
+  GST_RTSP_GET_PARAMETER    = (1 <<  2),
+  GST_RTSP_OPTIONS          = (1 <<  3),
+  GST_RTSP_PAUSE            = (1 <<  4),
+  GST_RTSP_PLAY             = (1 <<  5),
+  GST_RTSP_RECORD           = (1 <<  6),
+  GST_RTSP_REDIRECT         = (1 <<  7),
+  GST_RTSP_SETUP            = (1 <<  8),
+  GST_RTSP_SET_PARAMETER    = (1 <<  9),
+  GST_RTSP_TEARDOWN         = (1 << 10),
+} GstRTSPMethod;
+
+/* Authentication methods, ordered by strength */
+typedef enum {
+  GST_RTSP_AUTH_NONE    = 0x00,
+  GST_RTSP_AUTH_BASIC   = 0x01,
+  GST_RTSP_AUTH_DIGEST  = 0x02
+} GstRTSPAuthMethod;
+
+/* Strongest available authentication method */
+#define GST_RTSP_AUTH_MAX GST_RTSP_AUTH_DIGEST
+
+typedef enum {
+  GST_RTSP_HDR_INVALID,
+
+  /*
+   * R = Request
+   * r = response
+   * g = general
+   * e = entity
+   */
+  GST_RTSP_HDR_ACCEPT,              /* Accept               R      opt.      entity */
+  GST_RTSP_HDR_ACCEPT_ENCODING,     /* Accept-Encoding      R      opt.      entity */
+  GST_RTSP_HDR_ACCEPT_LANGUAGE,     /* Accept-Language      R      opt.      all */
+  GST_RTSP_HDR_ALLOW,               /* Allow                r      opt.      all */
+  GST_RTSP_HDR_AUTHORIZATION,       /* Authorization        R      opt.      all */
+  GST_RTSP_HDR_BANDWIDTH,           /* Bandwidth            R      opt.      all */
+  GST_RTSP_HDR_BLOCKSIZE,           /* Blocksize            R      opt.      all but OPTIONS, TEARDOWN */
+  GST_RTSP_HDR_CACHE_CONTROL,       /* Cache-Control        g      opt.      SETUP */
+  GST_RTSP_HDR_CONFERENCE,          /* Conference           R      opt.      SETUP */
+  GST_RTSP_HDR_CONNECTION,          /* Connection           g      req.      all */
+  GST_RTSP_HDR_CONTENT_BASE,        /* Content-Base         e      opt.      entity */
+  GST_RTSP_HDR_CONTENT_ENCODING,    /* Content-Encoding     e      req.      SET_PARAMETER, DESCRIBE, ANNOUNCE */
+  GST_RTSP_HDR_CONTENT_LANGUAGE,    /* Content-Language     e      req.      DESCRIBE, ANNOUNCE */
+  GST_RTSP_HDR_CONTENT_LENGTH,      /* Content-Length       e      req.      SET_PARAMETER, ANNOUNCE, entity */
+  GST_RTSP_HDR_CONTENT_LOCATION,    /* Content-Location     e      opt.      entity */
+  GST_RTSP_HDR_CONTENT_TYPE,        /* Content-Type         e      req.      SET_PARAMETER, ANNOUNCE, entity */
+  GST_RTSP_HDR_CSEQ,                /* CSeq                 g      req.      all */
+  GST_RTSP_HDR_DATE,                /* Date                 g      opt.      all */
+  GST_RTSP_HDR_EXPIRES,             /* Expires              e      opt.      DESCRIBE, ANNOUNCE */
+  GST_RTSP_HDR_FROM,                /* From                 R      opt.      all */
+  GST_RTSP_HDR_IF_MODIFIED_SINCE,   /* If-Modified-Since    R      opt.      DESCRIBE, SETUP */
+  GST_RTSP_HDR_LAST_MODIFIED,       /* Last-Modified        e      opt.      entity */
+  GST_RTSP_HDR_PROXY_AUTHENTICATE,  /* Proxy-Authenticate */
+  GST_RTSP_HDR_PROXY_REQUIRE,       /* Proxy-Require        R      req.      all */
+  GST_RTSP_HDR_PUBLIC,              /* Public               r      opt.      all */
+  GST_RTSP_HDR_RANGE,               /* Range                Rr     opt.      PLAY, PAUSE, RECORD */
+  GST_RTSP_HDR_REFERER,             /* Referer              R      opt.      all */
+  GST_RTSP_HDR_REQUIRE,             /* Require              R      req.      all */
+  GST_RTSP_HDR_RETRY_AFTER,         /* Retry-After          r      opt.      all */
+  GST_RTSP_HDR_RTP_INFO,            /* RTP-Info             r      req.      PLAY */
+  GST_RTSP_HDR_SCALE,               /* Scale                Rr     opt.      PLAY, RECORD */
+  GST_RTSP_HDR_SESSION,             /* Session              Rr     req.      all but SETUP, OPTIONS */
+  GST_RTSP_HDR_SERVER,              /* Server               r      opt.      all */
+  GST_RTSP_HDR_SPEED,               /* Speed                Rr     opt.      PLAY */
+  GST_RTSP_HDR_TRANSPORT,           /* Transport            Rr     req.      SETUP */
+  GST_RTSP_HDR_UNSUPPORTED,         /* Unsupported          r      req.      all */
+  GST_RTSP_HDR_USER_AGENT,          /* User-Agent           R      opt.      all */
+  GST_RTSP_HDR_VIA,                 /* Via                  g      opt.      all */
+  GST_RTSP_HDR_WWW_AUTHENTICATE,    /* WWW-Authenticate     r      opt.      all */
+
+  /* Real extensions */
+  GST_RTSP_HDR_CLIENT_CHALLENGE,    /* ClientChallenge */
+  GST_RTSP_HDR_REAL_CHALLENGE1,     /* RealChallenge1 */
+  GST_RTSP_HDR_REAL_CHALLENGE2,     /* RealChallenge2 */
+  GST_RTSP_HDR_REAL_CHALLENGE3,     /* RealChallenge3 */
+  GST_RTSP_HDR_SUBSCRIBE,           /* Subscribe */
+  GST_RTSP_HDR_ALERT,               /* Alert */
+  GST_RTSP_HDR_CLIENT_ID,           /* ClientID */
+  GST_RTSP_HDR_COMPANY_ID,          /* CompanyID */
+  GST_RTSP_HDR_GUID,                /* GUID */
+  GST_RTSP_HDR_REGION_DATA,         /* RegionData */
+  GST_RTSP_HDR_MAX_ASM_WIDTH,       /* SupportsMaximumASMBandwidth */
+  GST_RTSP_HDR_LANGUAGE,            /* Language */
+  GST_RTSP_HDR_PLAYER_START_TIME,   /* PlayerStarttime */
+
+
+} GstRTSPHeaderField;
+
+typedef enum {
+  GST_RTSP_STS_INVALID                              = 0, 
+  GST_RTSP_STS_CONTINUE                             = 100, 
+  GST_RTSP_STS_OK                                   = 200, 
+  GST_RTSP_STS_CREATED                              = 201, 
+  GST_RTSP_STS_LOW_ON_STORAGE                       = 250, 
+  GST_RTSP_STS_MULTIPLE_CHOICES                     = 300, 
+  GST_RTSP_STS_MOVED_PERMANENTLY                    = 301, 
+  GST_RTSP_STS_MOVE_TEMPORARILY                     = 302, 
+  GST_RTSP_STS_SEE_OTHER                            = 303, 
+  GST_RTSP_STS_NOT_MODIFIED                         = 304, 
+  GST_RTSP_STS_USE_PROXY                            = 305, 
+  GST_RTSP_STS_BAD_REQUEST                          = 400, 
+  GST_RTSP_STS_UNAUTHORIZED                         = 401, 
+  GST_RTSP_STS_PAYMENT_REQUIRED                     = 402, 
+  GST_RTSP_STS_FORBIDDEN                            = 403, 
+  GST_RTSP_STS_NOT_FOUND                            = 404, 
+  GST_RTSP_STS_METHOD_NOT_ALLOWED                   = 405, 
+  GST_RTSP_STS_NOT_ACCEPTABLE                       = 406, 
+  GST_RTSP_STS_PROXY_AUTH_REQUIRED                  = 407, 
+  GST_RTSP_STS_REQUEST_TIMEOUT                      = 408, 
+  GST_RTSP_STS_GONE                                 = 410, 
+  GST_RTSP_STS_LENGTH_REQUIRED                      = 411, 
+  GST_RTSP_STS_PRECONDITION_FAILED                  = 412, 
+  GST_RTSP_STS_REQUEST_ENTITY_TOO_LARGE             = 413, 
+  GST_RTSP_STS_REQUEST_URI_TOO_LARGE                = 414, 
+  GST_RTSP_STS_UNSUPPORTED_MEDIA_TYPE               = 415, 
+  GST_RTSP_STS_PARAMETER_NOT_UNDERSTOOD             = 451, 
+  GST_RTSP_STS_CONFERENCE_NOT_FOUND                 = 452, 
+  GST_RTSP_STS_NOT_ENOUGH_BANDWIDTH                 = 453, 
+  GST_RTSP_STS_SESSION_NOT_FOUND                    = 454, 
+  GST_RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE       = 455, 
+  GST_RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE  = 456, 
+  GST_RTSP_STS_INVALID_RANGE                        = 457, 
+  GST_RTSP_STS_PARAMETER_IS_READONLY                = 458, 
+  GST_RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED      = 459, 
+  GST_RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED     = 460, 
+  GST_RTSP_STS_UNSUPPORTED_TRANSPORT                = 461, 
+  GST_RTSP_STS_DESTINATION_UNREACHABLE              = 462, 
+  GST_RTSP_STS_INTERNAL_SERVER_ERROR                = 500, 
+  GST_RTSP_STS_NOT_IMPLEMENTED                      = 501, 
+  GST_RTSP_STS_BAD_GATEWAY                          = 502, 
+  GST_RTSP_STS_SERVICE_UNAVAILABLE                  = 503, 
+  GST_RTSP_STS_GATEWAY_TIMEOUT                      = 504, 
+  GST_RTSP_STS_RTSP_VERSION_NOT_SUPPORTED           = 505, 
+  GST_RTSP_STS_OPTION_NOT_SUPPORTED                 = 551, 
+} GstRTSPStatusCode;
+
+gchar*             gst_rtsp_strresult          (GstRTSPResult result);
+
+const gchar*       gst_rtsp_method_as_text     (GstRTSPMethod method);
+const gchar*       gst_rtsp_version_as_text    (GstRTSPVersion version);
+const gchar*       gst_rtsp_header_as_text     (GstRTSPHeaderField field);
+const gchar*       gst_rtsp_status_as_text     (GstRTSPStatusCode code);
+
+GstRTSPHeaderField gst_rtsp_find_header_field  (const gchar *header);
+GstRTSPMethod      gst_rtsp_find_method        (const gchar *method);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_DEFS_H__ */
diff --git a/gst-libs/gst/rtsp/gstrtspmessage.c b/gst-libs/gst/rtsp/gstrtspmessage.c
new file mode 100644 (file)
index 0000000..15f189f
--- /dev/null
@@ -0,0 +1,471 @@
+/* GStreamer
+ * Copyright (C) <2005,2006> Wim Taymans <wim@fluendo.com>
+ *               <2006> Lutz Mueller <lutz at topfrose dot de>
+ *
+ * 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.
+ */
+
+#include <string.h>
+
+#include "gstrtspmessage.h"
+
+typedef struct _RTSPKeyValue
+{
+  GstRTSPHeaderField field;
+  gchar *value;
+} RTSPKeyValue;
+
+static void
+key_value_foreach (GArray * array, GFunc func, gpointer user_data)
+{
+  guint i;
+
+  g_return_if_fail (array != NULL);
+
+  for (i = 0; i < array->len; i++) {
+    (*func) (&g_array_index (array, RTSPKeyValue, i), user_data);
+  }
+}
+
+GstRTSPResult
+gst_rtsp_message_new (GstRTSPMessage ** msg)
+{
+  GstRTSPMessage *newmsg;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  newmsg = g_new0 (GstRTSPMessage, 1);
+
+  *msg = newmsg;
+
+  return gst_rtsp_message_init (newmsg);
+}
+
+GstRTSPResult
+gst_rtsp_message_init (GstRTSPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_message_unset (msg);
+
+  msg->type = GST_RTSP_MESSAGE_INVALID;
+  msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_new_request (GstRTSPMessage ** msg, GstRTSPMethod method,
+    const gchar * uri)
+{
+  GstRTSPMessage *newmsg;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (uri != NULL, GST_RTSP_EINVAL);
+
+  newmsg = g_new0 (GstRTSPMessage, 1);
+
+  *msg = newmsg;
+
+  return gst_rtsp_message_init_request (newmsg, method, uri);
+}
+
+GstRTSPResult
+gst_rtsp_message_init_request (GstRTSPMessage * msg, GstRTSPMethod method,
+    const gchar * uri)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (uri != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_message_unset (msg);
+
+  msg->type = GST_RTSP_MESSAGE_REQUEST;
+  msg->type_data.request.method = method;
+  msg->type_data.request.uri = g_strdup (uri);
+  msg->type_data.request.version = GST_RTSP_VERSION_1_0;
+  msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_new_response (GstRTSPMessage ** msg, GstRTSPStatusCode code,
+    const gchar * reason, const GstRTSPMessage * request)
+{
+  GstRTSPMessage *newmsg;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  newmsg = g_new0 (GstRTSPMessage, 1);
+
+  *msg = newmsg;
+
+  return gst_rtsp_message_init_response (newmsg, code, reason, request);
+}
+
+GstRTSPResult
+gst_rtsp_message_init_response (GstRTSPMessage * msg, GstRTSPStatusCode code,
+    const gchar * reason, const GstRTSPMessage * request)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_message_unset (msg);
+
+  if (reason == NULL)
+    reason = gst_rtsp_status_as_text (code);
+
+  msg->type = GST_RTSP_MESSAGE_RESPONSE;
+  msg->type_data.response.code = code;
+  msg->type_data.response.reason = g_strdup (reason);
+  msg->type_data.response.version = GST_RTSP_VERSION_1_0;
+  msg->hdr_fields = g_array_new (FALSE, FALSE, sizeof (RTSPKeyValue));
+
+  if (request) {
+    gchar *header;
+
+    /* copy CSEQ */
+    if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_CSEQ, &header,
+            0) == GST_RTSP_OK) {
+      gst_rtsp_message_add_header (msg, GST_RTSP_HDR_CSEQ, header);
+    }
+
+    /* copy session id */
+    if (gst_rtsp_message_get_header (request, GST_RTSP_HDR_SESSION, &header,
+            0) == GST_RTSP_OK) {
+      char *pos;
+
+      header = g_strdup (header);
+      if ((pos = strchr (header, ';'))) {
+        *pos = '\0';
+      }
+      g_strchomp (header);
+      gst_rtsp_message_add_header (msg, GST_RTSP_HDR_SESSION, header);
+      g_free (header);
+    }
+
+    /* FIXME copy more headers? */
+  }
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_init_data (GstRTSPMessage * msg, guint8 channel)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_message_unset (msg);
+
+  msg->type = GST_RTSP_MESSAGE_DATA;
+  msg->type_data.data.channel = channel;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_unset (GstRTSPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  switch (msg->type) {
+    case GST_RTSP_MESSAGE_INVALID:
+      break;
+    case GST_RTSP_MESSAGE_REQUEST:
+      g_free (msg->type_data.request.uri);
+      break;
+    case GST_RTSP_MESSAGE_RESPONSE:
+      g_free (msg->type_data.response.reason);
+      break;
+    case GST_RTSP_MESSAGE_DATA:
+      break;
+    default:
+      g_assert_not_reached ();
+      break;
+  }
+
+  if (msg->hdr_fields != NULL)
+    g_array_free (msg->hdr_fields, TRUE);
+
+  g_free (msg->body);
+
+  memset (msg, 0, sizeof *msg);
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_free (GstRTSPMessage * msg)
+{
+  GstRTSPResult res;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  res = gst_rtsp_message_unset (msg);
+  if (res == GST_RTSP_OK)
+    g_free (msg);
+
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_message_add_header (GstRTSPMessage * msg, GstRTSPHeaderField field,
+    const gchar * value)
+{
+  RTSPKeyValue key_value;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (value != NULL, GST_RTSP_EINVAL);
+
+  key_value.field = field;
+  key_value.value = g_strdup (value);
+
+  g_array_append_val (msg->hdr_fields, key_value);
+
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_remove_header (GstRTSPMessage * msg, GstRTSPHeaderField field,
+    gint indx)
+{
+  GstRTSPResult res = GST_RTSP_ENOTIMPL;
+  guint i = 0;
+  gint cnt = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  while (i < msg->hdr_fields->len) {
+    RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+
+    if (key_value.field == field && (indx == -1 || cnt++ == indx)) {
+      g_array_remove_index (msg->hdr_fields, i);
+      res = GST_RTSP_OK;
+      if (indx != -1)
+        break;
+    } else {
+      i++;
+    }
+  }
+
+  return res;
+}
+
+GstRTSPResult
+gst_rtsp_message_get_header (const GstRTSPMessage * msg,
+    GstRTSPHeaderField field, gchar ** value, gint indx)
+{
+  guint i;
+  gint cnt = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  for (i = 0; i < msg->hdr_fields->len; i++) {
+    RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+
+    if (key_value.field == field && cnt++ == indx) {
+      if (value)
+        *value = key_value.value;
+      return GST_RTSP_OK;
+    }
+  }
+
+  return GST_RTSP_ENOTIMPL;
+}
+
+GstRTSPResult
+gst_rtsp_message_append_headers (const GstRTSPMessage * msg, GString * str)
+{
+  guint i;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (str != NULL, GST_RTSP_EINVAL);
+
+  for (i = 0; i < msg->hdr_fields->len; i++) {
+    RTSPKeyValue key_value = g_array_index (msg->hdr_fields, RTSPKeyValue, i);
+    const gchar *keystr = gst_rtsp_header_as_text (key_value.field);
+
+    g_string_append_printf (str, "%s: %s\r\n", keystr, key_value.value);
+  }
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_set_body (GstRTSPMessage * msg, const guint8 * data,
+    guint size)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  return gst_rtsp_message_take_body (msg, g_memdup (data, size), size);
+}
+
+GstRTSPResult
+gst_rtsp_message_take_body (GstRTSPMessage * msg, guint8 * data, guint size)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (data != NULL || size == 0, GST_RTSP_EINVAL);
+
+  if (msg->body)
+    g_free (msg->body);
+
+  msg->body = data;
+  msg->body_size = size;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_get_body (const GstRTSPMessage * msg, guint8 ** data,
+    guint * size)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (size != NULL, GST_RTSP_EINVAL);
+
+  *data = msg->body;
+  *size = msg->body_size;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_message_steal_body (GstRTSPMessage * msg, guint8 ** data, guint * size)
+{
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (data != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (size != NULL, GST_RTSP_EINVAL);
+
+  *data = msg->body;
+  *size = msg->body_size;
+
+  msg->body = NULL;
+  msg->body_size = 0;
+
+  return GST_RTSP_OK;
+}
+
+static void
+dump_mem (guint8 * mem, guint size)
+{
+  guint i, j;
+  GString *string = g_string_sized_new (50);
+  GString *chars = g_string_sized_new (18);
+
+  i = j = 0;
+  while (i < size) {
+    if (g_ascii_isprint (mem[i]))
+      g_string_append_printf (chars, "%c", mem[i]);
+    else
+      g_string_append_printf (chars, ".");
+
+    g_string_append_printf (string, "%02x ", mem[i]);
+
+    j++;
+    i++;
+
+    if (j == 16 || i == size) {
+      g_print ("%08x (%p): %-48.48s %-16.16s\n", i - j, mem + i - j,
+          string->str, chars->str);
+      g_string_set_size (string, 0);
+      g_string_set_size (chars, 0);
+      j = 0;
+    }
+  }
+  g_string_free (string, TRUE);
+  g_string_free (chars, TRUE);
+}
+
+static void
+dump_key_value (gpointer data, gpointer user_data)
+{
+  RTSPKeyValue *key_value = (RTSPKeyValue *) data;
+
+  g_print ("   key: '%s', value: '%s'\n",
+      gst_rtsp_header_as_text (key_value->field), key_value->value);
+}
+
+GstRTSPResult
+gst_rtsp_message_dump (GstRTSPMessage * msg)
+{
+  guint8 *data;
+  guint size;
+
+  g_return_val_if_fail (msg != NULL, GST_RTSP_EINVAL);
+
+  switch (msg->type) {
+    case GST_RTSP_MESSAGE_REQUEST:
+      g_print ("RTSP request message %p\n", msg);
+      g_print (" request line:\n");
+      g_print ("   method: '%s'\n",
+          gst_rtsp_method_as_text (msg->type_data.request.method));
+      g_print ("   uri:    '%s'\n", msg->type_data.request.uri);
+      g_print ("   version: '%s'\n",
+          gst_rtsp_version_as_text (msg->type_data.request.version));
+      g_print (" headers:\n");
+      key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
+      g_print (" body:\n");
+      gst_rtsp_message_get_body (msg, &data, &size);
+      dump_mem (data, size);
+      break;
+    case GST_RTSP_MESSAGE_RESPONSE:
+      g_print ("RTSP response message %p\n", msg);
+      g_print (" status line:\n");
+      g_print ("   code:   '%d'\n", msg->type_data.response.code);
+      g_print ("   reason: '%s'\n", msg->type_data.response.reason);
+      g_print ("   version: '%s'\n",
+          gst_rtsp_version_as_text (msg->type_data.response.version));
+      g_print (" headers:\n");
+      key_value_foreach (msg->hdr_fields, dump_key_value, NULL);
+      gst_rtsp_message_get_body (msg, &data, &size);
+      g_print (" body: length %d\n", size);
+      dump_mem (data, size);
+      break;
+    case GST_RTSP_MESSAGE_DATA:
+      g_print ("RTSP data message %p\n", msg);
+      g_print (" channel: '%d'\n", msg->type_data.data.channel);
+      g_print (" size:    '%d'\n", msg->body_size);
+      gst_rtsp_message_get_body (msg, &data, &size);
+      dump_mem (data, size);
+      break;
+    default:
+      g_print ("unsupported message type %d\n", msg->type);
+      return GST_RTSP_EINVAL;
+  }
+  return GST_RTSP_OK;
+}
diff --git a/gst-libs/gst/rtsp/gstrtspmessage.h b/gst-libs/gst/rtsp/gstrtspmessage.h
new file mode 100644 (file)
index 0000000..ee65422
--- /dev/null
@@ -0,0 +1,144 @@
+/* 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_RTSP_MESSAGE_H__
+#define __GST_RTSP_MESSAGE_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+  GST_RTSP_MESSAGE_INVALID,
+  GST_RTSP_MESSAGE_REQUEST,
+  GST_RTSP_MESSAGE_RESPONSE,
+  GST_RTSP_MESSAGE_DATA,
+} GstRTSPMsgType;
+
+typedef struct _GstRTSPMessage
+{
+  GstRTSPMsgType    type;
+
+  union {
+    struct {
+      GstRTSPMethod      method;
+      gchar             *uri;
+      GstRTSPVersion     version;
+    } request;
+    struct {
+      GstRTSPStatusCode  code;
+      gchar             *reason;
+      GstRTSPVersion     version;
+    } response;
+    struct {
+      guint8             channel;
+    } data;
+  } type_data;
+
+  GArray        *hdr_fields;
+
+  guint8        *body;
+  guint          body_size;
+
+} GstRTSPMessage;
+
+GstRTSPResult      gst_rtsp_message_new             (GstRTSPMessage **msg);
+GstRTSPResult      gst_rtsp_message_init            (GstRTSPMessage *msg);
+
+GstRTSPResult      gst_rtsp_message_new_request     (GstRTSPMessage **msg,
+                                                     GstRTSPMethod method,
+                                                     const gchar *uri);
+GstRTSPResult      gst_rtsp_message_init_request    (GstRTSPMessage *msg,
+                                                     GstRTSPMethod method,
+                                                     const gchar *uri);
+
+GstRTSPResult      gst_rtsp_message_new_response    (GstRTSPMessage **msg,
+                                                     GstRTSPStatusCode code,
+                                                     const gchar *reason,
+                                                     const GstRTSPMessage *request);
+GstRTSPResult      gst_rtsp_message_init_response   (GstRTSPMessage *msg,
+                                                     GstRTSPStatusCode code,
+                                                     const gchar *reason,
+                                                     const GstRTSPMessage *request);
+
+GstRTSPResult      gst_rtsp_message_init_data       (GstRTSPMessage *msg,
+                                                     guint8 channel);
+
+GstRTSPResult      gst_rtsp_message_unset           (GstRTSPMessage *msg);
+GstRTSPResult      gst_rtsp_message_free            (GstRTSPMessage *msg);
+
+
+GstRTSPResult      gst_rtsp_message_add_header      (GstRTSPMessage *msg,
+                                                     GstRTSPHeaderField field,
+                                                     const gchar *value);
+GstRTSPResult      gst_rtsp_message_remove_header   (GstRTSPMessage *msg,
+                                                     GstRTSPHeaderField field,
+                                                     gint indx);
+GstRTSPResult      gst_rtsp_message_get_header      (const GstRTSPMessage *msg,
+                                                     GstRTSPHeaderField field,
+                                                     gchar **value,
+                                                     gint indx);
+
+GstRTSPResult      gst_rtsp_message_append_headers  (const GstRTSPMessage *msg,
+                                                     GString *str);
+
+GstRTSPResult      gst_rtsp_message_set_body        (GstRTSPMessage *msg,
+                                                     const guint8 *data,
+                                                     guint size);
+GstRTSPResult      gst_rtsp_message_take_body       (GstRTSPMessage *msg,
+                                                     guint8 *data,
+                                                     guint size);
+GstRTSPResult      gst_rtsp_message_get_body        (const GstRTSPMessage *msg,
+                                                     guint8 **data,
+                                                     guint *size);
+GstRTSPResult      gst_rtsp_message_steal_body      (GstRTSPMessage *msg,
+                                                     guint8 **data,
+                                                     guint *size);
+
+GstRTSPResult      gst_rtsp_message_dump            (GstRTSPMessage *msg);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_MESSAGE_H__ */
diff --git a/gst-libs/gst/rtsp/gstrtsprange.c b/gst-libs/gst/rtsp/gstrtsprange.c
new file mode 100644 (file)
index 0000000..7ba8449
--- /dev/null
@@ -0,0 +1,176 @@
+/* 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.
+ */
+
+#include <stdio.h>
+#include <string.h>
+
+#include "gstrtsprange.h"
+
+/* npt-time     =   "now" | npt-sec | npt-hhmmss
+ * npt-sec      =   1*DIGIT [ "." *DIGIT ]
+ * npt-hhmmss   =   npt-hh ":" npt-mm ":" npt-ss [ "." *DIGIT ]
+ * npt-hh       =   1*DIGIT     ; any positive number
+ * npt-mm       =   1*2DIGIT    ; 0-59
+ * npt-ss       =   1*2DIGIT    ; 0-59
+ */
+static GstRTSPResult
+parse_npt_time (const gchar * str, GstRTSPTime * time)
+{
+  if (strcmp (str, "now") == 0) {
+    time->type = GST_RTSP_TIME_NOW;
+  } else if (str[0] == '\0') {
+    time->type = GST_RTSP_TIME_END;
+  } else if (strstr (str, ":")) {
+    gfloat seconds;
+    gint hours, mins;
+
+    sscanf (str, "%2d:%2d:%f", &hours, &mins, &seconds);
+
+    time->type = GST_RTSP_TIME_SECONDS;
+    time->seconds = ((hours * 60) + mins) * 60 + seconds;
+  } else {
+    gfloat seconds;
+
+    sscanf (str, "%f", &seconds);
+
+    time->type = GST_RTSP_TIME_SECONDS;
+    time->seconds = seconds;
+  }
+  return GST_RTSP_OK;
+}
+
+/* npt-range    =   ( npt-time "-" [ npt-time ] ) | ( "-" npt-time )
+ */
+static GstRTSPResult
+parse_npt_range (const gchar * str, GstRTSPTimeRange * range)
+{
+  GstRTSPResult res;
+  gchar *p;
+
+  range->unit = GST_RTSP_RANGE_NPT;
+
+  /* find '-' separator */
+  p = strstr (str, "-");
+  if (p == NULL)
+    return GST_RTSP_EINVAL;
+
+  if ((res = parse_npt_time (str, &range->min)) != GST_RTSP_OK)
+    goto done;
+
+  res = parse_npt_time (p + 1, &range->max);
+
+done:
+  return res;
+}
+
+static GstRTSPResult
+parse_clock_range (const gchar * str, GstRTSPTimeRange * range)
+{
+  return GST_RTSP_ENOTIMPL;
+}
+
+static GstRTSPResult
+parse_smpte_range (const gchar * str, GstRTSPTimeRange * range)
+{
+  return GST_RTSP_ENOTIMPL;
+}
+
+/**
+ * rtsp_range_parse:
+ * @rangestr: a range string to parse
+ * @range: location to hold the #GstRTSPTimeRange result
+ *
+ * Parse @rangestr to a #GstRTSPTimeRange.
+ *
+ * Returns: #GST_RTSP_OK on success.
+ */
+GstRTSPResult
+gst_rtsp_range_parse (const gchar * rangestr, GstRTSPTimeRange ** range)
+{
+  GstRTSPResult ret;
+  GstRTSPTimeRange *res;
+  gchar *p;
+
+  g_return_val_if_fail (rangestr != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (range != NULL, GST_RTSP_EINVAL);
+
+  res = g_new0 (GstRTSPTimeRange, 1);
+
+  p = (gchar *) rangestr;
+  /* first figure out the units of the range */
+  if (g_str_has_prefix (p, "npt=")) {
+    ret = parse_npt_range (p + 4, res);
+  } else if (g_str_has_prefix (p, "clock=")) {
+    ret = parse_clock_range (p + 6, res);
+  } else if (g_str_has_prefix (p, "smpte=")) {
+    res->unit = GST_RTSP_RANGE_SMPTE;
+    ret = parse_smpte_range (p + 6, res);
+  } else if (g_str_has_prefix (p, "smpte-30-drop=")) {
+    res->unit = GST_RTSP_RANGE_SMPTE_30_DROP;
+    ret = parse_smpte_range (p + 14, res);
+  } else if (g_str_has_prefix (p, "smpte-25=")) {
+    res->unit = GST_RTSP_RANGE_SMPTE_25;
+    ret = parse_smpte_range (p + 9, res);
+  } else
+    goto invalid;
+
+  if (ret == GST_RTSP_OK)
+    *range = res;
+
+  return ret;
+
+  /* ERRORS */
+invalid:
+  {
+    gst_rtsp_range_free (res);
+    return GST_RTSP_EINVAL;
+  }
+}
+
+void
+gst_rtsp_range_free (GstRTSPTimeRange * range)
+{
+  if (range == NULL)
+    return;
+
+  g_free (range);
+}
diff --git a/gst-libs/gst/rtsp/gstrtsprange.h b/gst-libs/gst/rtsp/gstrtsprange.h
new file mode 100644 (file)
index 0000000..d18e464
--- /dev/null
@@ -0,0 +1,97 @@
+/* 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_RTSP_RANGE_H__
+#define __GST_RTSP_RANGE_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstRTSPRangeUnit:
+ * @GST_RTSP_RANGE_SMPTE:
+ * @GST_RTSP_RANGE_SMPTE_30_DROP:
+ * @GST_RTSP_RANGE_SMPTE_25:
+ * @GST_RTSP_RANGE_NPT:
+ * @GST_RTSP_RANGE_CLOCK:
+ *
+ * Different possible time range units.
+ */
+typedef enum
+{
+  GST_RTSP_RANGE_SMPTE,
+  GST_RTSP_RANGE_SMPTE_30_DROP,
+  GST_RTSP_RANGE_SMPTE_25,
+  GST_RTSP_RANGE_NPT,
+  GST_RTSP_RANGE_CLOCK
+} GstRTSPRangeUnit;
+
+typedef struct _GstRTSPTimeRange GstRTSPTimeRange;
+typedef struct _GstRTSPTime GstRTSPTime;
+
+typedef enum {
+  GST_RTSP_TIME_SECONDS,
+  GST_RTSP_TIME_NOW,
+  GST_RTSP_TIME_END
+} GstRTSPTimeType;
+
+struct _GstRTSPTime {
+  GstRTSPTimeType type;
+  gdouble         seconds;
+};
+
+struct _GstRTSPTimeRange {
+  GstRTSPRangeUnit unit;
+
+  GstRTSPTime min;
+  GstRTSPTime max;
+};
+
+GstRTSPResult   gst_rtsp_range_parse        (const gchar *rangestr, GstRTSPTimeRange **range);
+void            gst_rtsp_range_free         (GstRTSPTimeRange *range);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_RANGE_H__ */
diff --git a/gst-libs/gst/rtsp/gstrtsptransport.c b/gst-libs/gst/rtsp/gstrtsptransport.c
new file mode 100644 (file)
index 0000000..080167e
--- /dev/null
@@ -0,0 +1,589 @@
+/* GStreamer
+ * Copyright (C) <2005,2006,2007> Wim Taymans <wim@fluendo.com>
+ *               <2007> Peter Kjellerstedt  <pkj at axis 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.
+ */
+
+#include <string.h>
+#include <stdlib.h>
+
+#include "gstrtsptransport.h"
+
+#define MAX_MANAGERS   2
+
+typedef enum
+{
+  RTSP_TRANSPORT_DELIVERY = 1 << 0,     /* multicast | unicast */
+  RTSP_TRANSPORT_DESTINATION = 1 << 1,
+  RTSP_TRANSPORT_SOURCE = 1 << 2,
+  RTSP_TRANSPORT_INTERLEAVED = 1 << 3,
+  RTSP_TRANSPORT_APPEND = 1 << 4,
+  RTSP_TRANSPORT_TTL = 1 << 5,
+  RTSP_TRANSPORT_LAYERS = 1 << 6,
+  RTSP_TRANSPORT_PORT = 1 << 7,
+  RTSP_TRANSPORT_CLIENT_PORT = 1 << 8,
+  RTSP_TRANSPORT_SERVER_PORT = 1 << 9,
+  RTSP_TRANSPORT_SSRC = 1 << 10,
+  RTSP_TRANSPORT_MODE = 1 << 11,
+} RTSPTransportParameter;
+
+typedef struct
+{
+  const gchar *name;
+  const GstRTSPTransMode mode;
+  const gchar *gst_mime;
+  const gchar *manager[MAX_MANAGERS];
+} GstRTSPTransMap;
+
+static const GstRTSPTransMap transports[] = {
+  {"rtp", GST_RTSP_TRANS_RTP, "application/x-rtp", {"gstrtpbin", "rtpdec"}},
+  {"x-real-rdt", GST_RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+  {"x-pn-tng", GST_RTSP_TRANS_RDT, "application/x-rdt", {NULL, NULL}},
+  {NULL, GST_RTSP_TRANS_UNKNOWN, NULL, {NULL, NULL}}
+};
+
+typedef struct
+{
+  const gchar *name;
+  const GstRTSPProfile profile;
+} RTSPProfileMap;
+
+static const RTSPProfileMap profiles[] = {
+  {"avp", GST_RTSP_PROFILE_AVP},
+  {"savp", GST_RTSP_PROFILE_SAVP},
+  {NULL, GST_RTSP_PROFILE_UNKNOWN}
+};
+
+typedef struct
+{
+  const gchar *name;
+  const GstRTSPLowerTrans ltrans;
+} RTSPLTransMap;
+
+static const RTSPLTransMap ltrans[] = {
+  {"udp", GST_RTSP_LOWER_TRANS_UDP},
+  {"mcast", GST_RTSP_LOWER_TRANS_UDP_MCAST},
+  {"tcp", GST_RTSP_LOWER_TRANS_TCP},
+  {NULL, GST_RTSP_LOWER_TRANS_UNKNOWN}
+};
+
+#define RTSP_TRANSPORT_PARAMETER_IS_UNIQUE(param) \
+G_STMT_START {                                    \
+  if ((transport_params & (param)) != 0)          \
+    goto invalid_transport;                       \
+  transport_params |= (param);                    \
+} G_STMT_END
+
+GstRTSPResult
+gst_rtsp_transport_new (GstRTSPTransport ** transport)
+{
+  GstRTSPTransport *trans;
+
+  g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+  trans = g_new0 (GstRTSPTransport, 1);
+
+  *transport = trans;
+
+  return gst_rtsp_transport_init (trans);
+}
+
+GstRTSPResult
+gst_rtsp_transport_init (GstRTSPTransport * transport)
+{
+  g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+  g_free (transport->destination);
+  g_free (transport->source);
+
+  memset (transport, 0, sizeof (GstRTSPTransport));
+
+  transport->trans = GST_RTSP_TRANS_RTP;
+  transport->profile = GST_RTSP_PROFILE_AVP;
+  transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+  transport->mode_play = TRUE;
+  transport->mode_record = FALSE;
+  transport->interleaved.min = -1;
+  transport->interleaved.max = -1;
+  transport->port.min = -1;
+  transport->port.max = -1;
+  transport->client_port.min = -1;
+  transport->client_port.max = -1;
+  transport->server_port.min = -1;
+  transport->server_port.max = -1;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_transport_get_mime (GstRTSPTransMode trans, const gchar ** mime)
+{
+  gint i;
+
+  g_return_val_if_fail (mime != NULL, GST_RTSP_EINVAL);
+
+  for (i = 0; transports[i].name; i++)
+    if (transports[i].mode == trans)
+      break;
+  *mime = transports[i].gst_mime;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_transport_get_manager (GstRTSPTransMode trans, const gchar ** manager,
+    guint option)
+{
+  gint i;
+
+  g_return_val_if_fail (manager != NULL, GST_RTSP_EINVAL);
+
+  for (i = 0; transports[i].name; i++)
+    if (transports[i].mode == trans)
+      break;
+
+  if (option < MAX_MANAGERS)
+    *manager = transports[i].manager[option];
+  else
+    *manager = NULL;
+
+  return GST_RTSP_OK;
+}
+
+static void
+parse_mode (GstRTSPTransport * transport, const gchar * str)
+{
+  transport->mode_play = (strstr (str, "play") != NULL);
+  transport->mode_record = (strstr (str, "record") != NULL);
+}
+
+static void
+parse_range (const gchar * str, GstRTSPRange * range)
+{
+  gchar *minus;
+  gchar *tmp;
+
+  /* even though strtol() allows white space, plus and minus in front of
+   * the number, we do not allow it
+   */
+  if (g_ascii_isspace (*str) || *str == '+' || *str == '-')
+    goto invalid_range;
+
+  minus = strstr (str, "-");
+  if (minus) {
+    if (g_ascii_isspace (minus[1]) || minus[1] == '+' || minus[1] == '-')
+      goto invalid_range;
+
+    range->min = strtol (str, &tmp, 10);
+    if (str == tmp || tmp != minus)
+      goto invalid_range;
+
+    range->max = strtol (minus + 1, &tmp, 10);
+    if (*tmp && *tmp != ';')
+      goto invalid_range;
+  } else {
+    range->min = strtol (str, &tmp, 10);
+    if (str == tmp || (*tmp && *tmp != ';'))
+      goto invalid_range;
+
+    range->max = -1;
+  }
+
+  return;
+
+invalid_range:
+  {
+    range->min = -1;
+    range->max = -1;
+    return;
+  }
+}
+
+static gchar *
+range_as_text (const GstRTSPRange * range)
+{
+  if (range->min < 0)
+    return NULL;
+  else if (range->max < 0)
+    return g_strdup_printf ("%d", range->min);
+  else
+    return g_strdup_printf ("%d-%d", range->min, range->max);
+}
+
+static const gchar *
+rtsp_transport_mode_as_text (const GstRTSPTransport * transport)
+{
+  gint i;
+
+  for (i = 0; transports[i].name; i++)
+    if (transports[i].mode == transport->trans)
+      return transports[i].name;
+
+  return NULL;
+}
+
+static const gchar *
+rtsp_transport_profile_as_text (const GstRTSPTransport * transport)
+{
+  gint i;
+
+  for (i = 0; profiles[i].name; i++)
+    if (profiles[i].profile == transport->profile)
+      return profiles[i].name;
+
+  return NULL;
+}
+
+static const gchar *
+rtsp_transport_ltrans_as_text (const GstRTSPTransport * transport)
+{
+  gint i;
+
+  /* need to special case GST_RTSP_LOWER_TRANS_UDP_MCAST */
+  if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+    return "udp";
+
+  for (i = 0; ltrans[i].name; i++)
+    if (ltrans[i].ltrans == transport->lower_transport)
+      return ltrans[i].name;
+
+  return NULL;
+}
+
+GstRTSPResult
+gst_rtsp_transport_parse (const gchar * str, GstRTSPTransport * transport)
+{
+  gchar **split, *down, **transp = NULL;
+  guint transport_params = 0;
+  gint i;
+
+  g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (str != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_transport_init (transport);
+
+  /* case insensitive */
+  down = g_ascii_strdown (str, -1);
+
+  split = g_strsplit (down, ";", 0);
+  g_free (down);
+
+  /* First field contains the transport/profile/lower_transport */
+  if (split[0] == NULL)
+    goto invalid_transport;
+
+  transp = g_strsplit (split[0], "/", 0);
+
+  if (transp[0] == NULL || transp[1] == NULL)
+    goto invalid_transport;
+
+  for (i = 0; transports[i].name; i++)
+    if (strcmp (transp[0], transports[i].name) == 0)
+      break;
+  transport->trans = transports[i].mode;
+
+  for (i = 0; profiles[i].name; i++)
+    if (strcmp (transp[1], profiles[i].name) == 0)
+      break;
+  transport->profile = profiles[i].profile;
+
+  if (transp[2] != NULL) {
+    for (i = 0; ltrans[i].name; i++)
+      if (strcmp (transp[2], ltrans[i].name) == 0)
+        break;
+    transport->lower_transport = ltrans[i].ltrans;
+  } else {
+    /* specifying the lower transport is optional */
+    if (transport->trans == GST_RTSP_TRANS_RTP &&
+        transport->profile == GST_RTSP_PROFILE_AVP)
+      transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+    else
+      transport->lower_transport = GST_RTSP_LOWER_TRANS_UNKNOWN;
+  }
+
+  g_strfreev (transp);
+  transp = NULL;
+
+  if (transport->trans == GST_RTSP_TRANS_UNKNOWN ||
+      transport->profile == GST_RTSP_PROFILE_UNKNOWN ||
+      transport->lower_transport == GST_RTSP_LOWER_TRANS_UNKNOWN)
+    goto unsupported_transport;
+
+  i = 1;
+  while (split[i]) {
+    if (strcmp (split[i], "multicast") == 0) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
+      if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP)
+        goto invalid_transport;
+      transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
+    } else if (strcmp (split[i], "unicast") == 0) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
+      if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+        transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP;
+    } else if (g_str_has_prefix (split[i], "destination=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DESTINATION);
+      transport->destination = g_strdup (split[i] + 12);
+    } else if (g_str_has_prefix (split[i], "source=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SOURCE);
+      transport->source = g_strdup (split[i] + 7);
+    } else if (g_str_has_prefix (split[i], "layers=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_LAYERS);
+      transport->layers = strtoul (split[i] + 7, NULL, 10);
+    } else if (g_str_has_prefix (split[i], "mode=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_MODE);
+      parse_mode (transport, split[i] + 5);
+      if (!transport->mode_play && !transport->mode_record)
+        goto invalid_transport;
+    } else if (strcmp (split[i], "append") == 0) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_APPEND);
+      transport->append = TRUE;
+    } else if (g_str_has_prefix (split[i], "interleaved=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_INTERLEAVED);
+      parse_range (split[i] + 12, &transport->interleaved);
+      if (transport->interleaved.min < 0 ||
+          transport->interleaved.min >= 256 ||
+          transport->interleaved.max >= 256)
+        goto invalid_transport;
+    } else if (g_str_has_prefix (split[i], "ttl=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_TTL);
+      transport->ttl = strtoul (split[i] + 4, NULL, 10);
+      if (transport->ttl >= 256)
+        goto invalid_transport;
+    } else if (g_str_has_prefix (split[i], "port=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_PORT);
+      parse_range (split[i] + 5, &transport->port);
+      if (transport->port.min < 0 ||
+          transport->port.min >= 65536 || transport->port.max >= 65536)
+        goto invalid_transport;
+    } else if (g_str_has_prefix (split[i], "client_port=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_CLIENT_PORT);
+      parse_range (split[i] + 12, &transport->client_port);
+      if (transport->client_port.min < 0 ||
+          transport->client_port.min >= 65536 ||
+          transport->client_port.max >= 65536)
+        goto invalid_transport;
+    } else if (g_str_has_prefix (split[i], "server_port=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SERVER_PORT);
+      parse_range (split[i] + 12, &transport->server_port);
+      if (transport->server_port.min < 0 ||
+          transport->server_port.min >= 65536 ||
+          transport->server_port.max >= 65536)
+        goto invalid_transport;
+    } else if (g_str_has_prefix (split[i], "ssrc=")) {
+      RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SSRC);
+      transport->ssrc = strtoul (split[i] + 5, NULL, 16);
+    } else {
+      /* unknown field... */
+      g_warning ("unknown transport field \"%s\"", split[i]);
+    }
+    i++;
+  }
+  g_strfreev (split);
+
+  return GST_RTSP_OK;
+
+unsupported_transport:
+  {
+    g_strfreev (split);
+    return GST_RTSP_ERROR;
+  }
+invalid_transport:
+  {
+    g_strfreev (transp);
+    g_strfreev (split);
+    return GST_RTSP_EINVAL;
+  }
+}
+
+gchar *
+gst_rtsp_transport_as_text (GstRTSPTransport * transport)
+{
+  GPtrArray *strs;
+  gchar *res;
+  const gchar *tmp;
+
+  g_return_val_if_fail (transport != NULL, NULL);
+
+  strs = g_ptr_array_new ();
+
+  /* add the transport specifier */
+  if ((tmp = rtsp_transport_mode_as_text (transport)) == NULL)
+    goto invalid_transport;
+  g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+
+  g_ptr_array_add (strs, g_strdup ("/"));
+
+  if ((tmp = rtsp_transport_profile_as_text (transport)) == NULL)
+    goto invalid_transport;
+  g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+
+  if (transport->trans != GST_RTSP_TRANS_RTP ||
+      transport->profile != GST_RTSP_PROFILE_AVP ||
+      transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
+    g_ptr_array_add (strs, g_strdup ("/"));
+
+    if ((tmp = rtsp_transport_ltrans_as_text (transport)) == NULL)
+      goto invalid_transport;
+    g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
+  }
+
+  /*
+   * the order of the following parameters is the same as the one specified in
+   * RFC 2326 to please some weird RTSP clients that require it
+   */
+
+  /* add the unicast/multicast parameter */
+  if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
+    g_ptr_array_add (strs, g_strdup (";multicast"));
+  else
+    g_ptr_array_add (strs, g_strdup (";unicast"));
+
+  /* add the destination parameter */
+  if (transport->destination != NULL) {
+    g_ptr_array_add (strs, g_strdup (";destination="));
+    g_ptr_array_add (strs, g_strdup (transport->destination));
+  }
+
+  /* add the source parameter */
+  if (transport->source != NULL) {
+    g_ptr_array_add (strs, g_strdup (";source="));
+    g_ptr_array_add (strs, g_strdup (transport->source));
+  }
+
+  /* add the interleaved parameter */
+  if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP &&
+      transport->interleaved.min >= 0) {
+    if (transport->interleaved.min < 256 && transport->interleaved.max < 256) {
+      g_ptr_array_add (strs, g_strdup (";interleaved="));
+      g_ptr_array_add (strs, range_as_text (&transport->interleaved));
+    } else
+      goto invalid_transport;
+  }
+
+  /* add the append parameter */
+  if (transport->mode_record && transport->append)
+    g_ptr_array_add (strs, g_strdup (";append"));
+
+  /* add the ttl parameter */
+  if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST &&
+      transport->ttl != 0) {
+    if (transport->ttl < 256) {
+      g_ptr_array_add (strs, g_strdup (";ttl="));
+      g_ptr_array_add (strs, g_strdup_printf ("%u", transport->ttl));
+    } else
+      goto invalid_transport;
+  }
+
+  /* add the layers parameter */
+  if (transport->layers != 0) {
+    g_ptr_array_add (strs, g_strdup (";layers="));
+    g_ptr_array_add (strs, g_strdup_printf ("%u", transport->layers));
+  }
+
+  /* add the port parameter */
+  if (transport->trans == GST_RTSP_TRANS_RTP && transport->port.min >= 0) {
+    if (transport->port.min < 65536 && transport->port.max < 65536) {
+      g_ptr_array_add (strs, g_strdup (";port="));
+      g_ptr_array_add (strs, range_as_text (&transport->port));
+    } else
+      goto invalid_transport;
+  }
+
+  /* add the client_port parameter */
+  if (transport->trans == GST_RTSP_TRANS_RTP && transport->client_port.min >= 0) {
+    if (transport->client_port.min < 65536 &&
+        transport->client_port.max < 65536) {
+      g_ptr_array_add (strs, g_strdup (";client_port="));
+      g_ptr_array_add (strs, range_as_text (&transport->client_port));
+    } else
+      goto invalid_transport;
+  }
+
+  /* add the server_port parameter */
+  if (transport->trans == GST_RTSP_TRANS_RTP && transport->server_port.min >= 0) {
+    if (transport->server_port.min < 65536 &&
+        transport->server_port.max < 65536) {
+      g_ptr_array_add (strs, g_strdup (";server_port="));
+      g_ptr_array_add (strs, range_as_text (&transport->server_port));
+    } else
+      goto invalid_transport;
+  }
+
+  /* add the ssrc parameter */
+  if (transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST &&
+      transport->ssrc != 0) {
+    g_ptr_array_add (strs, g_strdup (";ssrc="));
+    g_ptr_array_add (strs, g_strdup_printf ("%08X", transport->ssrc));
+  }
+
+  /* add the mode parameter */
+  if (transport->mode_play && transport->mode_record)
+    g_ptr_array_add (strs, g_strdup (";mode=\"PLAY,RECORD\""));
+  else if (transport->mode_record)
+    g_ptr_array_add (strs, g_strdup (";mode=\"RECORD\""));
+  else if (transport->mode_play)
+    g_ptr_array_add (strs, g_strdup (";mode=\"PLAY\""));
+
+  /* add a terminating NULL */
+  g_ptr_array_add (strs, NULL);
+
+  res = g_strjoinv (NULL, (gchar **) strs->pdata);
+  g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
+
+  return res;
+
+invalid_transport:
+  {
+    g_ptr_array_add (strs, NULL);
+    g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
+    return NULL;
+  }
+}
+
+GstRTSPResult
+gst_rtsp_transport_free (GstRTSPTransport * transport)
+{
+  g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
+
+  gst_rtsp_transport_init (transport);
+  g_free (transport);
+
+  return GST_RTSP_OK;
+}
diff --git a/gst-libs/gst/rtsp/gstrtsptransport.h b/gst-libs/gst/rtsp/gstrtsptransport.h
new file mode 100644 (file)
index 0000000..39e4fdd
--- /dev/null
@@ -0,0 +1,151 @@
+/* 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_RTSP_TRANSPORT_H__
+#define __GST_RTSP_TRANSPORT_H__
+
+#include <gst/rtsp/gstrtspdefs.h>
+
+G_BEGIN_DECLS
+
+/**
+ * GstRTSPTransMode:
+ * @GST_RTSP_TRANS_UNKNOWN: invalid tansport mode
+ * @GST_RTSP_TRANS_RTP: transfer RTP data
+ * @GST_RTSP_TRANS_RDT: transfer RDT (RealMedia) data
+ *
+ * The transfer mode to use.
+ */
+typedef enum {
+  GST_RTSP_TRANS_UNKNOWN =  0,
+  GST_RTSP_TRANS_RTP     = (1 << 0),
+  GST_RTSP_TRANS_RDT     = (1 << 1)
+} GstRTSPTransMode;
+
+/**
+ * GstRTSPProfile:
+ * @GST_RTSP_PROFILE_UNKNOWN: invalid profile
+ * @GST_RTSP_PROFILE_AVP: the Audio/Visual profile
+ * @GST_RTSP_PROFILE_SAVP: the secure Audio/Visual profile
+ *
+ * The transfer profile to use.
+ */
+typedef enum {
+  GST_RTSP_PROFILE_UNKNOWN =  0,
+  GST_RTSP_PROFILE_AVP     = (1 << 0),
+  GST_RTSP_PROFILE_SAVP    = (1 << 1)
+} GstRTSPProfile;
+
+/**
+ * GstRTSPLowerTrans:
+ * @GST_RTSP_LOWER_TRANS_UNKNOWN: invalid transport flag
+ * @GST_RTSP_LOWER_TRANS_UDP: stream data over UDP
+ * @GST_RTSP_LOWER_TRANS_UDP_MCAST: stream data over UDP multicast
+ * @GST_RTSP_LOWER_TRANS_TCP: stream data over TCP
+ *
+ * The different transport methods.
+ */
+typedef enum {
+  GST_RTSP_LOWER_TRANS_UNKNOWN   = 0,
+  GST_RTSP_LOWER_TRANS_UDP       = (1 << 0),
+  GST_RTSP_LOWER_TRANS_UDP_MCAST = (1 << 1),
+  GST_RTSP_LOWER_TRANS_TCP       = (1 << 2)
+} GstRTSPLowerTrans;
+
+/**
+ * RTSPRange:
+ * @min: minimum value of the range
+ * @max: maximum value of the range
+ *
+ * A type to specify a range.
+ */
+typedef struct
+{
+  gint min;
+  gint max;
+} GstRTSPRange;
+
+/**
+ * GstRTSPTransport:
+ *
+ * A structure holding the RTSP transport values.
+ */
+typedef struct _GstRTSPTransport {
+  /*< private >*/
+  GstRTSPTransMode  trans;
+  GstRTSPProfile    profile;
+  GstRTSPLowerTrans lower_transport;
+
+  gchar         *destination;
+  gchar         *source;
+  guint          layers;
+  gboolean       mode_play;
+  gboolean       mode_record;
+  gboolean       append;
+  GstRTSPRange   interleaved;
+
+  /* multicast specific */
+  guint  ttl;
+
+  /* UDP specific */
+  GstRTSPRange   port;
+  GstRTSPRange   client_port;
+  GstRTSPRange   server_port;
+  /* RTP specific */
+  guint          ssrc;
+
+} GstRTSPTransport;
+
+GstRTSPResult      gst_rtsp_transport_new          (GstRTSPTransport **transport);
+GstRTSPResult      gst_rtsp_transport_init         (GstRTSPTransport *transport);
+
+GstRTSPResult      gst_rtsp_transport_parse        (const gchar *str, GstRTSPTransport *transport);
+gchar*             gst_rtsp_transport_as_text      (GstRTSPTransport *transport);
+
+GstRTSPResult      gst_rtsp_transport_get_mime     (GstRTSPTransMode trans, const gchar **mime);
+GstRTSPResult      gst_rtsp_transport_get_manager  (GstRTSPTransMode trans, const gchar **manager, guint option);
+
+GstRTSPResult      gst_rtsp_transport_free         (GstRTSPTransport *transport);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_TRANSPORT_H__ */
diff --git a/gst-libs/gst/rtsp/gstrtspurl.c b/gst-libs/gst/rtsp/gstrtspurl.c
new file mode 100644 (file)
index 0000000..34ce971
--- /dev/null
@@ -0,0 +1,211 @@
+/* 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstrtspurl.h"
+
+#define RTSP_PROTO      "rtsp://"
+#define RTSP_PROTO_LEN  7
+#define RTSPU_PROTO     "rtspu://"
+#define RTSPU_PROTO_LEN 8
+#define RTSPT_PROTO     "rtspt://"
+#define RTSPT_PROTO_LEN 8
+
+/* format is rtsp[u]://[user:passwd@]host[:port]/abspath[?query] */
+
+GstRTSPResult
+gst_rtsp_url_parse (const gchar * urlstr, GstRTSPUrl ** url)
+{
+  GstRTSPUrl *res;
+  gchar *p, *delim, *at, *col;
+
+  g_return_val_if_fail (urlstr != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+
+  res = g_new0 (GstRTSPUrl, 1);
+
+  p = (gchar *) urlstr;
+  if (g_str_has_prefix (p, RTSP_PROTO)) {
+    res->transports =
+        GST_RTSP_LOWER_TRANS_TCP | GST_RTSP_LOWER_TRANS_UDP |
+        GST_RTSP_LOWER_TRANS_UDP_MCAST;
+    p += RTSP_PROTO_LEN;
+  } else if (g_str_has_prefix (p, RTSPU_PROTO)) {
+    res->transports = GST_RTSP_LOWER_TRANS_UDP | GST_RTSP_LOWER_TRANS_UDP_MCAST;
+    p += RTSPU_PROTO_LEN;
+  } else if (g_str_has_prefix (p, RTSPT_PROTO)) {
+    res->transports = GST_RTSP_LOWER_TRANS_TCP;
+    p += RTSPT_PROTO_LEN;
+  } else
+    goto invalid;
+
+  delim = strpbrk (p, "/?");
+  at = strchr (p, '@');
+
+  if (at && delim && at > delim)
+    at = NULL;
+
+  if (at) {
+    col = strchr (p, ':');
+
+    /* must have a ':' and it must be before the '@' */
+    if (col == NULL || col > at)
+      goto invalid;
+
+    res->user = g_strndup (p, col - p);
+    col++;
+    res->passwd = g_strndup (col, at - col);
+
+    /* move to host */
+    p = at + 1;
+  }
+
+  col = strchr (p, ':');
+  /* we have a ':' and a delimiter but the ':' is after the delimiter, it's
+   * not really part of the hostname */
+  if (col && delim && col >= delim)
+    col = NULL;
+
+  if (col) {
+    res->host = g_strndup (p, col - p);
+    p = col + 1;
+    res->port = strtoul (p, (char **) &p, 10);
+    if (delim)
+      p = delim;
+  } else {
+    /* no port specified, set to 0. _get_port() will return the default port. */
+    res->port = 0;
+    if (!delim) {
+      res->host = g_strdup (p);
+      p = NULL;
+    } else {
+      res->host = g_strndup (p, delim - p);
+      p = delim;
+    }
+  }
+
+  if (p && *p == '/') {
+    delim = strchr (p, '?');
+    if (!delim) {
+      res->abspath = g_strdup (p);
+      p = NULL;
+    } else {
+      res->abspath = g_strndup (p, delim - p);
+      p = delim;
+    }
+  } else {
+    res->abspath = g_strdup ("/");
+  }
+
+  if (p && *p == '?')
+    res->query = g_strdup (p + 1);
+
+  *url = res;
+
+  return GST_RTSP_OK;
+
+  /* ERRORS */
+invalid:
+  {
+    gst_rtsp_url_free (res);
+    return GST_RTSP_EINVAL;
+  }
+}
+
+void
+gst_rtsp_url_free (GstRTSPUrl * url)
+{
+  if (url == NULL)
+    return;
+
+  g_free (url->user);
+  g_free (url->passwd);
+  g_free (url->host);
+  g_free (url->abspath);
+  g_free (url->query);
+  g_free (url);
+}
+
+GstRTSPResult
+gst_rtsp_url_set_port (GstRTSPUrl * url, guint16 port)
+{
+  g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+
+  url->port = port;
+
+  return GST_RTSP_OK;
+}
+
+GstRTSPResult
+gst_rtsp_url_get_port (GstRTSPUrl * url, guint16 * port)
+{
+  g_return_val_if_fail (url != NULL, GST_RTSP_EINVAL);
+  g_return_val_if_fail (port != NULL, GST_RTSP_EINVAL);
+
+  /* if a port was specified, use that else use the default port. */
+  if (url->port != 0)
+    *port = url->port;
+  else
+    *port = GST_RTSP_DEFAULT_PORT;
+
+  return GST_RTSP_OK;
+}
+
+gchar *
+gst_rtsp_url_get_request_uri (GstRTSPUrl * url)
+{
+  gchar *uri;
+
+  g_return_val_if_fail (url != NULL, NULL);
+
+  if (url->port != 0) {
+    uri = g_strdup_printf ("rtsp://%s:%u%s%s%s", url->host, url->port,
+        url->abspath, url->query ? "?" : "", url->query ? url->query : "");
+  } else {
+    uri = g_strdup_printf ("rtsp://%s%s%s%s", url->host, url->abspath,
+        url->query ? "?" : "", url->query ? url->query : "");
+  }
+
+  return uri;
+}
diff --git a/gst-libs/gst/rtsp/gstrtspurl.h b/gst-libs/gst/rtsp/gstrtspurl.h
new file mode 100644 (file)
index 0000000..cbe6cca
--- /dev/null
@@ -0,0 +1,77 @@
+/* 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_RTSP_URL_H__
+#define __GST_RTSP_URL_H__
+
+#include <glib.h>
+
+#include <gst/rtsp/gstrtspdefs.h>
+#include <gst/rtsp/gstrtsptransport.h>
+
+G_BEGIN_DECLS
+
+#define GST_RTSP_DEFAULT_PORT       554
+
+typedef struct _GstRTSPUrl GstRTSPUrl;
+
+struct _GstRTSPUrl {
+  GstRTSPLowerTrans  transports;
+  GstRTSPFamily      family;
+  gchar             *user;
+  gchar             *passwd;
+  gchar             *host;
+  guint16            port;
+  gchar             *abspath;
+  gchar             *query;
+}; 
+
+GstRTSPResult      gst_rtsp_url_parse           (const gchar *urlstr, GstRTSPUrl **url);
+void               gst_rtsp_url_free            (GstRTSPUrl *url);
+gchar*             gst_rtsp_url_get_request_uri (GstRTSPUrl *url);
+
+GstRTSPResult      gst_rtsp_url_set_port        (GstRTSPUrl *url, guint16 port);
+GstRTSPResult      gst_rtsp_url_get_port        (GstRTSPUrl *url, guint16 *port);
+
+G_END_DECLS
+
+#endif /* __GST_RTSP_URL_H__ */
diff --git a/gst-libs/gst/sdp/Makefile.am b/gst-libs/gst/sdp/Makefile.am
new file mode 100644 (file)
index 0000000..fedab63
--- /dev/null
@@ -0,0 +1,12 @@
+libgstsdpincludedir = $(includedir)/gstreamer-@GST_MAJORMINOR@/gst/sdp
+
+libgstsdpinclude_HEADERS = gstsdp.h            \
+                          gstsdpmessage.h
+
+lib_LTLIBRARIES = libgstsdp-@GST_MAJORMINOR@.la
+
+libgstsdp_@GST_MAJORMINOR@_la_SOURCES = gstsdpmessage.c
+
+libgstsdp_@GST_MAJORMINOR@_la_CFLAGS = $(GST_PLUGINS_BASE_CFLAGS) $(GST_BASE_CFLAGS) $(GST_CFLAGS)
+libgstsdp_@GST_MAJORMINOR@_la_LIBADD = $(GST_LIBS)
+libgstsdp_@GST_MAJORMINOR@_la_LDFLAGS = $(GST_LIB_LDFLAGS) $(GST_ALL_LDFLAGS) $(GST_LT_LDFLAGS)
diff --git a/gst-libs/gst/sdp/gstsdp.h b/gst-libs/gst/sdp/gstsdp.h
new file mode 100644 (file)
index 0000000..a16518f
--- /dev/null
@@ -0,0 +1,51 @@
+/* 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_SDP_H__
+#define __GST_SDP_H__
+
+typedef enum {
+  GST_SDP_OK     = 0,
+  GST_SDP_EINVAL = -1
+} GstSDPResult;
+
+#endif /* __GST_SDP_H__ */
diff --git a/gst-libs/gst/sdp/gstsdpmessage.c b/gst-libs/gst/sdp/gstsdpmessage.c
new file mode 100644 (file)
index 0000000..2bf7f8a
--- /dev/null
@@ -0,0 +1,936 @@
+/* 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.
+ */
+
+#include <stdlib.h>
+#include <string.h>
+
+#include "gstsdpmessage.h"
+
+/* FIXME, is currently allocated on the stack */
+#define MAX_LINE_LEN   1024 * 16
+
+#define FREE_STRING(field)      g_free ((field)); (field) = NULL;
+#define FREE_ARRAY(field)       \
+G_STMT_START {                  \
+  if (field)                    \
+    g_array_free (field, TRUE); \
+  field = NULL;                 \
+} G_STMT_END
+#define REPLACE_STRING(field,val)       FREE_STRING(field);field=g_strdup (val);
+
+#define INIT_ARRAY(field,type,init_func)               \
+G_STMT_START {                                         \
+  if (field) {                                         \
+    guint i;                                           \
+    for(i=0; i<field->len; i++)                                \
+      init_func (&g_array_index(field, type, i));      \
+    g_array_set_size (field,0);                        \
+  }                                                    \
+  else                                                 \
+    field = g_array_new (FALSE, TRUE, sizeof(type));    \
+} G_STMT_END
+
+#define DEFINE_STRING_SETTER(field)                                     \
+GstSDPResult gst_sdp_message_set_##field (GstSDPMessage *msg, gchar *val) {      \
+  g_free (msg->field);                                                  \
+  msg->field = g_strdup (val);                                          \
+  return GST_SDP_OK;                                                       \
+}
+#define DEFINE_STRING_GETTER(field)                                     \
+char* gst_sdp_message_get_##field (GstSDPMessage *msg) {                       \
+  return msg->field;                                                    \
+}
+
+#define DEFINE_ARRAY_LEN(field)                                         \
+gint gst_sdp_message_##field##_len (GstSDPMessage *msg) {                      \
+  return ((msg)->field->len);                                           \
+}
+#define DEFINE_ARRAY_GETTER(method,field,type)                          \
+type gst_sdp_message_get_##method (GstSDPMessage *msg, guint idx) {            \
+  return g_array_index ((msg)->field, type, idx);                       \
+}
+#define DEFINE_ARRAY_P_GETTER(method,field,type)                        \
+type * gst_sdp_message_get_##method (GstSDPMessage *msg, guint idx) {          \
+  return &g_array_index ((msg)->field, type, idx);                      \
+}
+#define DEFINE_ARRAY_ADDER(method,field,type,dup_method)                \
+GstSDPResult gst_sdp_message_add_##method (GstSDPMessage *msg, type val) {       \
+  type v = dup_method(val);                                             \
+  g_array_append_val((msg)->field, v);                                  \
+  return GST_SDP_OK;                                                       \
+}
+
+static void
+gst_sdp_origin_init (GstSDPOrigin * origin)
+{
+  FREE_STRING (origin->username);
+  FREE_STRING (origin->sess_id);
+  FREE_STRING (origin->sess_version);
+  FREE_STRING (origin->nettype);
+  FREE_STRING (origin->addrtype);
+  FREE_STRING (origin->addr);
+}
+
+static void
+gst_sdp_connection_init (GstSDPConnection * connection)
+{
+  FREE_STRING (connection->nettype);
+  FREE_STRING (connection->addrtype);
+  FREE_STRING (connection->address);
+  connection->ttl = 0;
+  connection->addr_number = 0;
+}
+
+static void
+gst_sdp_bandwidth_init (GstSDPBandwidth * bandwidth)
+{
+  FREE_STRING (bandwidth->bwtype);
+  bandwidth->bandwidth = 0;
+}
+
+static void
+gst_sdp_time_init (GstSDPTime * time)
+{
+  FREE_STRING (time->start);
+  FREE_STRING (time->stop);
+  time->n_repeat = 0;
+}
+
+static void
+gst_sdp_zone_init (GstSDPZone * zone)
+{
+  FREE_STRING (zone->time);
+  FREE_STRING (zone->typed_time);
+}
+
+static void
+gst_sdp_key_init (GstSDPKey * key)
+{
+  FREE_STRING (key->type);
+  FREE_STRING (key->data);
+}
+
+static void
+gst_sdp_attribute_init (GstSDPAttribute * attr)
+{
+  FREE_STRING (attr->key);
+  FREE_STRING (attr->value);
+}
+
+/**
+ * gst_sdp_message_new:
+ * @msg: pointer to new #GstSDPMessage
+ *
+ * Allocate a new GstSDPMessage and store the result in @msg.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_new (GstSDPMessage ** msg)
+{
+  GstSDPMessage *newmsg;
+
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+  newmsg = g_new0 (GstSDPMessage, 1);
+
+  *msg = newmsg;
+
+  return gst_sdp_message_init (newmsg);
+}
+
+/**
+ * gst_sdp_message_init:
+ * @msg: an #GstSDPMessage
+ *
+ * Initialize @msg so that its contents are as if it was freshly allocated
+ * with gst_sdp_message_new(). This function is mostly used to initialize a message
+ * allocated on the stack. gst_sdp_message_uninit() undoes this operation.
+ *
+ * When this function is invoked on newly allocated data (with malloc or on the
+ * stack), its contents should be set to 0 before calling this function.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_init (GstSDPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+  FREE_STRING (msg->version);
+  gst_sdp_origin_init (&msg->origin);
+  FREE_STRING (msg->session_name);
+  FREE_STRING (msg->information);
+  FREE_STRING (msg->uri);
+  INIT_ARRAY (msg->emails, gchar *, g_free);
+  INIT_ARRAY (msg->phones, gchar *, g_free);
+  gst_sdp_connection_init (&msg->connection);
+  INIT_ARRAY (msg->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
+  INIT_ARRAY (msg->times, GstSDPTime, gst_sdp_time_init);
+  INIT_ARRAY (msg->zones, GstSDPZone, gst_sdp_zone_init);
+  gst_sdp_key_init (&msg->key);
+  INIT_ARRAY (msg->attributes, GstSDPAttribute, gst_sdp_attribute_init);
+  INIT_ARRAY (msg->medias, GstSDPMedia, gst_sdp_media_uninit);
+
+  return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_message_uninit:
+ * @msg: an #GstSDPMessage
+ *
+ * Free all resources allocated in @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was allocated on the
+ * stack and initialized with gst_sdp_message_init().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_uninit (GstSDPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+  gst_sdp_message_init (msg);
+
+  FREE_ARRAY (msg->emails);
+  FREE_ARRAY (msg->phones);
+  FREE_ARRAY (msg->bandwidths);
+  FREE_ARRAY (msg->times);
+  FREE_ARRAY (msg->zones);
+  FREE_ARRAY (msg->attributes);
+  FREE_ARRAY (msg->medias);
+
+  return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_message_free:
+ * @msg: an #GstSDPMessage
+ *
+ * Free all resources allocated by @msg. @msg should not be used anymore after
+ * this function. This function should be used when @msg was dynamically
+ * allocated with gst_sdp_message_new().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_free (GstSDPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+  gst_sdp_message_uninit (msg);
+  g_free (msg);
+
+  return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_new:
+ * @media: pointer to new #GstSDPMedia
+ *
+ * Allocate a new GstSDPMedia and store the result in @media.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_new (GstSDPMedia ** media)
+{
+  GstSDPMedia *newmedia;
+
+  g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+  newmedia = g_new0 (GstSDPMedia, 1);
+
+  *media = newmedia;
+
+  return gst_sdp_media_init (newmedia);
+}
+
+/**
+ * gst_sdp_media_init:
+ * @media: a #GstSDPMedia
+ *
+ * Initialize @media so that its contents are as if it was freshly allocated
+ * with gst_sdp_media_new(). This function is mostly used to initialize a media
+ * allocated on the stack. gst_sdp_media_uninit() undoes this operation.
+ *
+ * When this function is invoked on newly allocated data (with malloc or on the
+ * stack), its contents should be set to 0 before calling this function.
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_init (GstSDPMedia * media)
+{
+  g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+  FREE_STRING (media->media);
+  media->port = 0;
+  media->num_ports = 0;
+  FREE_STRING (media->proto);
+  INIT_ARRAY (media->fmts, gchar *, g_free);
+  FREE_STRING (media->information);
+  INIT_ARRAY (media->connections, GstSDPConnection, gst_sdp_connection_init);
+  INIT_ARRAY (media->bandwidths, GstSDPBandwidth, gst_sdp_bandwidth_init);
+  gst_sdp_key_init (&media->key);
+  INIT_ARRAY (media->attributes, GstSDPAttribute, gst_sdp_attribute_init);
+
+  return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_uninit:
+ * @media: an #GstSDPMedia
+ *
+ * Free all resources allocated in @media. @media should not be used anymore after
+ * this function. This function should be used when @media was allocated on the
+ * stack and initialized with gst_sdp_media_init().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_uninit (GstSDPMedia * media)
+{
+  g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+  gst_sdp_media_init (media);
+  FREE_ARRAY (media->fmts);
+  FREE_ARRAY (media->connections);
+  FREE_ARRAY (media->bandwidths);
+  FREE_ARRAY (media->attributes);
+
+  return GST_SDP_OK;
+}
+
+/**
+ * gst_sdp_media_free:
+ * @media: an #GstSDPMedia
+ *
+ * Free all resources allocated by @media. @media should not be used anymore after
+ * this function. This function should be used when @media was dynamically
+ * allocated with gst_sdp_media_new().
+ *
+ * Returns: a #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_media_free (GstSDPMedia * media)
+{
+  g_return_val_if_fail (media != NULL, GST_SDP_EINVAL);
+
+  gst_sdp_media_uninit (media);
+  g_free (media);
+
+  return GST_SDP_OK;
+}
+
+DEFINE_STRING_SETTER (version);
+DEFINE_STRING_GETTER (version);
+
+GstSDPResult
+gst_sdp_message_set_origin (GstSDPMessage * msg, gchar * username,
+    gchar * sess_id, gchar * sess_version, gchar * nettype, gchar * addrtype,
+    gchar * addr)
+{
+  REPLACE_STRING (msg->origin.username, username);
+  REPLACE_STRING (msg->origin.sess_id, sess_id);
+  REPLACE_STRING (msg->origin.sess_version, sess_version);
+  REPLACE_STRING (msg->origin.nettype, nettype);
+  REPLACE_STRING (msg->origin.addrtype, addrtype);
+  REPLACE_STRING (msg->origin.addr, addr);
+  return GST_SDP_OK;
+}
+
+GstSDPOrigin *
+gst_sdp_message_get_origin (GstSDPMessage * msg)
+{
+  return &msg->origin;
+}
+
+DEFINE_STRING_SETTER (session_name);
+DEFINE_STRING_GETTER (session_name);
+DEFINE_STRING_SETTER (information);
+DEFINE_STRING_GETTER (information);
+DEFINE_STRING_SETTER (uri);
+DEFINE_STRING_GETTER (uri);
+
+DEFINE_ARRAY_LEN (emails);
+DEFINE_ARRAY_GETTER (email, emails, gchar *);
+DEFINE_ARRAY_ADDER (email, emails, gchar *, g_strdup);
+
+DEFINE_ARRAY_LEN (phones);
+DEFINE_ARRAY_GETTER (phone, phones, gchar *);
+DEFINE_ARRAY_ADDER (phone, phones, gchar *, g_strdup);
+
+GstSDPResult
+gst_sdp_message_set_connection (GstSDPMessage * msg, gchar * nettype,
+    gchar * addrtype, gchar * address, gint ttl, gint addr_number)
+{
+  REPLACE_STRING (msg->connection.nettype, nettype);
+  REPLACE_STRING (msg->connection.addrtype, addrtype);
+  REPLACE_STRING (msg->connection.address, address);
+  msg->connection.ttl = ttl;
+  msg->connection.addr_number = addr_number;
+  return GST_SDP_OK;
+}
+
+GstSDPConnection *
+gst_sdp_message_get_connection (GstSDPMessage * msg)
+{
+  return &msg->connection;
+}
+
+DEFINE_ARRAY_LEN (bandwidths);
+DEFINE_ARRAY_P_GETTER (bandwidth, bandwidths, GstSDPBandwidth);
+
+GstSDPResult
+gst_sdp_message_add_bandwidth (GstSDPMessage * msg, gchar * bwtype,
+    gint bandwidth)
+{
+  GstSDPBandwidth bw;
+
+  bw.bwtype = g_strdup (bwtype);
+  bw.bandwidth = bandwidth;
+
+  g_array_append_val (msg->bandwidths, bw);
+
+  return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (times);
+DEFINE_ARRAY_P_GETTER (time, times, GstSDPTime);
+
+GstSDPResult
+gst_sdp_message_add_time (GstSDPMessage * msg, gchar * time)
+{
+  return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (zones);
+DEFINE_ARRAY_P_GETTER (zone, zones, GstSDPZone);
+GstSDPResult
+gst_sdp_message_add_zone (GstSDPMessage * msg, gchar * time, gchar * typed_time)
+{
+  GstSDPZone zone;
+
+  zone.time = g_strdup (time);
+  zone.typed_time = g_strdup (typed_time);
+
+  g_array_append_val (msg->zones, zone);
+
+  return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_message_set_key (GstSDPMessage * msg, gchar * type, gchar * data)
+{
+  REPLACE_STRING (msg->key.type, type);
+  REPLACE_STRING (msg->key.data, data);
+  return GST_SDP_OK;
+}
+
+GstSDPKey *
+gst_sdp_message_get_key (GstSDPMessage * msg)
+{
+  return &msg->key;
+}
+
+
+DEFINE_ARRAY_LEN (attributes);
+DEFINE_ARRAY_P_GETTER (attribute, attributes, GstSDPAttribute);
+gchar *
+gst_sdp_message_get_attribute_val_n (GstSDPMessage * msg, gchar * key,
+    guint nth)
+{
+  guint i;
+
+  for (i = 0; i < msg->attributes->len; i++) {
+    GstSDPAttribute *attr;
+
+    attr = &g_array_index (msg->attributes, GstSDPAttribute, i);
+    if (!strcmp (attr->key, key)) {
+      if (nth == 0)
+        return attr->value;
+      else
+        nth--;
+    }
+  }
+  return NULL;
+}
+
+gchar *
+gst_sdp_message_get_attribute_val (GstSDPMessage * msg, gchar * key)
+{
+  return gst_sdp_message_get_attribute_val_n (msg, key, 0);
+}
+
+GstSDPResult
+gst_sdp_message_add_attribute (GstSDPMessage * msg, gchar * key, gchar * value)
+{
+  GstSDPAttribute attr;
+
+  attr.key = g_strdup (key);
+  attr.value = g_strdup (value);
+
+  g_array_append_val (msg->attributes, attr);
+
+  return GST_SDP_OK;
+}
+
+DEFINE_ARRAY_LEN (medias);
+DEFINE_ARRAY_P_GETTER (media, medias, GstSDPMedia);
+
+/**
+ * gst_sdp_message_add_media:
+ * @msg: an #GstSDPMessage
+ * @media: an #GstSDPMedia to add
+ *
+ * Adds @media to the array of medias in @msg. This function takes ownership of
+ * the contents of @media so that @media will have to be reinitialized with
+ * gst_media_init() before it can be used again.
+ *
+ * Returns: an #GstSDPResult.
+ */
+GstSDPResult
+gst_sdp_message_add_media (GstSDPMessage * msg, GstSDPMedia * media)
+{
+  gint len;
+  GstSDPMedia *nmedia;
+
+  len = msg->medias->len;
+  g_array_set_size (msg->medias, len + 1);
+  nmedia = &g_array_index (msg->medias, GstSDPMedia, len);
+
+  memcpy (nmedia, media, sizeof (GstSDPMedia));
+  memset (media, 0, sizeof (GstSDPMedia));
+
+  return GST_SDP_OK;
+}
+
+/* media access */
+
+GstSDPResult
+gst_sdp_media_add_attribute (GstSDPMedia * media, gchar * key, gchar * value)
+{
+  GstSDPAttribute attr;
+
+  attr.key = g_strdup (key);
+  attr.value = g_strdup (value);
+
+  g_array_append_val (media->attributes, attr);
+
+  return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_media_add_bandwidth (GstSDPMedia * media, gchar * bwtype,
+    gint bandwidth)
+{
+  GstSDPBandwidth bw;
+
+  bw.bwtype = g_strdup (bwtype);
+  bw.bandwidth = bandwidth;
+
+  g_array_append_val (media->bandwidths, bw);
+
+  return GST_SDP_OK;
+}
+
+GstSDPResult
+gst_sdp_media_add_format (GstSDPMedia * media, gchar * format)
+{
+  gchar *fmt;
+
+  fmt = g_strdup (format);
+
+  g_array_append_val (media->fmts, fmt);
+
+  return GST_SDP_OK;
+}
+
+GstSDPAttribute *
+gst_sdp_media_get_attribute (GstSDPMedia * media, guint idx)
+{
+  return &g_array_index (media->attributes, GstSDPAttribute, idx);
+}
+
+gchar *
+gst_sdp_media_get_attribute_val_n (GstSDPMedia * media, gchar * key, guint nth)
+{
+  guint i;
+
+  for (i = 0; i < media->attributes->len; i++) {
+    GstSDPAttribute *attr;
+
+    attr = &g_array_index (media->attributes, GstSDPAttribute, i);
+    if (!strcmp (attr->key, key)) {
+      if (nth == 0)
+        return attr->value;
+      else
+        nth--;
+    }
+  }
+  return NULL;
+}
+
+gchar *
+gst_sdp_media_get_attribute_val (GstSDPMedia * media, gchar * key)
+{
+  return gst_sdp_media_get_attribute_val_n (media, key, 0);
+}
+
+gchar *
+gst_sdp_media_get_format (GstSDPMedia * media, guint idx)
+{
+  if (idx >= media->fmts->len)
+    return NULL;
+  return g_array_index (media->fmts, gchar *, idx);
+}
+
+static void
+read_string (gchar * dest, guint size, gchar ** src)
+{
+  guint idx;
+
+  idx = 0;
+  /* skip spaces */
+  while (g_ascii_isspace (**src))
+    (*src)++;
+
+  while (!g_ascii_isspace (**src) && **src != '\0') {
+    if (idx < size - 1)
+      dest[idx++] = **src;
+    (*src)++;
+  }
+  if (size > 0)
+    dest[idx] = '\0';
+}
+
+static void
+read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
+{
+  guint idx;
+
+  idx = 0;
+  /* skip spaces */
+  while (g_ascii_isspace (**src))
+    (*src)++;
+
+  while (**src != del && **src != '\0') {
+    if (idx < size - 1)
+      dest[idx++] = **src;
+    (*src)++;
+  }
+  if (size > 0)
+    dest[idx] = '\0';
+}
+
+enum
+{
+  SDP_SESSION,
+  SDP_MEDIA,
+};
+
+typedef struct
+{
+  gint state;
+  GstSDPMessage *msg;
+  GstSDPMedia *media;
+} SDPContext;
+
+static gboolean
+gst_sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
+{
+  gchar str[8192];
+  gchar *p = buffer;
+
+#define READ_STRING(field) read_string (str, sizeof(str), &p);REPLACE_STRING (field, str);
+#define READ_INT(field) read_string (str, sizeof(str), &p);field = atoi(str);
+
+  switch (type) {
+    case 'v':
+      if (buffer[0] != '0')
+        g_warning ("wrong SDP version");
+      gst_sdp_message_set_version (c->msg, buffer);
+      break;
+    case 'o':
+      READ_STRING (c->msg->origin.username);
+      READ_STRING (c->msg->origin.sess_id);
+      READ_STRING (c->msg->origin.sess_version);
+      READ_STRING (c->msg->origin.nettype);
+      READ_STRING (c->msg->origin.addrtype);
+      READ_STRING (c->msg->origin.addr);
+      break;
+    case 's':
+      REPLACE_STRING (c->msg->session_name, buffer);
+      break;
+    case 'i':
+      if (c->state == SDP_SESSION) {
+        REPLACE_STRING (c->msg->information, buffer);
+      } else {
+        REPLACE_STRING (c->media->information, buffer);
+      }
+      break;
+    case 'u':
+      REPLACE_STRING (c->msg->uri, buffer);
+      break;
+    case 'e':
+      gst_sdp_message_add_email (c->msg, buffer);
+      break;
+    case 'p':
+      gst_sdp_message_add_phone (c->msg, buffer);
+      break;
+    case 'c':
+      READ_STRING (c->msg->connection.nettype);
+      READ_STRING (c->msg->connection.addrtype);
+      READ_STRING (c->msg->connection.address);
+      READ_INT (c->msg->connection.ttl);
+      READ_INT (c->msg->connection.addr_number);
+      break;
+    case 'b':
+    {
+      gchar str2[MAX_LINE_LEN];
+
+      read_string_del (str, sizeof (str), ':', &p);
+      read_string (str2, sizeof (str2), &p);
+      if (c->state == SDP_SESSION)
+        gst_sdp_message_add_bandwidth (c->msg, str, atoi (str2));
+      else
+        gst_sdp_media_add_bandwidth (c->media, str, atoi (str2));
+      break;
+    }
+    case 't':
+      break;
+    case 'k':
+
+      break;
+    case 'a':
+      read_string_del (str, sizeof (str), ':', &p);
+      if (*p != '\0')
+        p++;
+      if (c->state == SDP_SESSION)
+        gst_sdp_message_add_attribute (c->msg, str, p);
+      else
+        gst_sdp_media_add_attribute (c->media, str, p);
+      break;
+    case 'm':
+    {
+      gchar *slash;
+      GstSDPMedia nmedia;
+
+      c->state = SDP_MEDIA;
+      memset (&nmedia, 0, sizeof (nmedia));
+      gst_sdp_media_init (&nmedia);
+
+      READ_STRING (nmedia.media);
+      read_string (str, sizeof (str), &p);
+      slash = g_strrstr (str, "/");
+      if (slash) {
+        *slash = '\0';
+        nmedia.port = atoi (str);
+        nmedia.num_ports = atoi (slash + 1);
+      } else {
+        nmedia.port = atoi (str);
+        nmedia.num_ports = -1;
+      }
+      READ_STRING (nmedia.proto);
+      do {
+        read_string (str, sizeof (str), &p);
+        gst_sdp_media_add_format (&nmedia, str);
+      } while (*p != '\0');
+
+      gst_sdp_message_add_media (c->msg, &nmedia);
+      c->media =
+          &g_array_index (c->msg->medias, GstSDPMedia, c->msg->medias->len - 1);
+      break;
+    }
+    default:
+      break;
+  }
+  return TRUE;
+}
+
+GstSDPResult
+gst_sdp_message_parse_buffer (guint8 * data, guint size, GstSDPMessage * msg)
+{
+  gchar *p;
+  SDPContext c;
+  gchar type;
+  gchar buffer[MAX_LINE_LEN];
+  guint idx = 0;
+
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+  g_return_val_if_fail (data != NULL, GST_SDP_EINVAL);
+  g_return_val_if_fail (size != 0, GST_SDP_EINVAL);
+
+  c.state = SDP_SESSION;
+  c.msg = msg;
+  c.media = NULL;
+
+  p = (gchar *) data;
+  while (TRUE) {
+    while (g_ascii_isspace (*p))
+      p++;
+
+    type = *p++;
+    if (type == '\0')
+      break;
+
+    if (*p != '=')
+      goto line_done;
+    p++;
+
+    idx = 0;
+    while (*p != '\n' && *p != '\r' && *p != '\0') {
+      if (idx < sizeof (buffer) - 1)
+        buffer[idx++] = *p;
+      p++;
+    }
+    buffer[idx] = '\0';
+    gst_sdp_parse_line (&c, type, buffer);
+
+  line_done:
+    while (*p != '\n' && *p != '\0')
+      p++;
+    if (*p == '\n')
+      p++;
+  }
+
+  return GST_SDP_OK;
+}
+
+static void
+print_media (GstSDPMedia * media)
+{
+  g_print ("   media:       '%s'\n", media->media);
+  g_print ("   port:        '%d'\n", media->port);
+  g_print ("   num_ports:   '%d'\n", media->num_ports);
+  g_print ("   proto:       '%s'\n", media->proto);
+  if (media->fmts->len > 0) {
+    guint i;
+
+    g_print ("   formats:\n");
+    for (i = 0; i < media->fmts->len; i++) {
+      g_print ("    format  '%s'\n", g_array_index (media->fmts, gchar *, i));
+    }
+  }
+  g_print ("   information: '%s'\n", media->information);
+  g_print ("   key:\n");
+  g_print ("    type:       '%s'\n", media->key.type);
+  g_print ("    data:       '%s'\n", media->key.data);
+  if (media->attributes->len > 0) {
+    guint i;
+
+    g_print ("   attributes:\n");
+    for (i = 0; i < media->attributes->len; i++) {
+      GstSDPAttribute *attr =
+          &g_array_index (media->attributes, GstSDPAttribute, i);
+
+      g_print ("    attribute '%s' : '%s'\n", attr->key, attr->value);
+    }
+  }
+}
+
+GstSDPResult
+gst_sdp_message_dump (GstSDPMessage * msg)
+{
+  g_return_val_if_fail (msg != NULL, GST_SDP_EINVAL);
+
+  g_print ("sdp packet %p:\n", msg);
+  g_print (" version:       '%s'\n", msg->version);
+  g_print (" origin:\n");
+  g_print ("  username:     '%s'\n", msg->origin.username);
+  g_print ("  sess_id:      '%s'\n", msg->origin.sess_id);
+  g_print ("  sess_version: '%s'\n", msg->origin.sess_version);
+  g_print ("  nettype:      '%s'\n", msg->origin.nettype);
+  g_print ("  addrtype:     '%s'\n", msg->origin.addrtype);
+  g_print ("  addr:         '%s'\n", msg->origin.addr);
+  g_print (" session_name:  '%s'\n", msg->session_name);
+  g_print (" information:   '%s'\n", msg->information);
+  g_print (" uri:           '%s'\n", msg->uri);
+
+  if (msg->emails->len > 0) {
+    guint i;
+
+    g_print (" emails:\n");
+    for (i = 0; i < msg->emails->len; i++) {
+      g_print ("  email '%s'\n", g_array_index (msg->emails, gchar *, i));
+    }
+  }
+  if (msg->phones->len > 0) {
+    guint i;
+
+    g_print (" phones:\n");
+    for (i = 0; i < msg->phones->len; i++) {
+      g_print ("  phone '%s'\n", g_array_index (msg->phones, gchar *, i));
+    }
+  }
+  g_print (" connection:\n");
+  g_print ("  nettype:      '%s'\n", msg->connection.nettype);
+  g_print ("  addrtype:     '%s'\n", msg->connection.addrtype);
+  g_print ("  address:      '%s'\n", msg->connection.address);
+  g_print ("  ttl:          '%d'\n", msg->connection.ttl);
+  g_print ("  addr_number:  '%d'\n", msg->connection.addr_number);
+  g_print (" key:\n");
+  g_print ("  type:         '%s'\n", msg->key.type);
+  g_print ("  data:         '%s'\n", msg->key.data);
+  if (msg->attributes->len > 0) {
+    guint i;
+
+    g_print (" attributes:\n");
+    for (i = 0; i < msg->attributes->len; i++) {
+      GstSDPAttribute *attr =
+          &g_array_index (msg->attributes, GstSDPAttribute, i);
+
+      g_print ("  attribute '%s' : '%s'\n", attr->key, attr->value);
+    }
+  }
+  if (msg->medias->len > 0) {
+    guint i;
+
+    g_print (" medias:\n");
+    for (i = 0; i < msg->medias->len; i++) {
+      g_print ("  media %d:\n", i);
+      print_media (&g_array_index (msg->medias, GstSDPMedia, i));
+    }
+  }
+  return GST_SDP_OK;
+}
diff --git a/gst-libs/gst/sdp/gstsdpmessage.h b/gst-libs/gst/sdp/gstsdpmessage.h
new file mode 100644 (file)
index 0000000..e381ace
--- /dev/null
@@ -0,0 +1,200 @@
+/* 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_SDP_MESSAGE_H__
+#define __GST_SDP_MESSAGE_H__
+
+#include <glib.h>
+
+#include <gst/sdp/gstsdp.h>
+
+G_BEGIN_DECLS
+
+typedef struct {
+  gchar *username;
+  gchar *sess_id;
+  gchar *sess_version;
+  gchar *nettype;
+  gchar *addrtype;
+  gchar *addr;
+} GstSDPOrigin;
+
+typedef struct {
+  gchar *nettype; 
+  gchar *addrtype; 
+  gchar *address;
+  gint   ttl;
+  gint   addr_number;
+} GstSDPConnection;
+
+#define GST_SDP_BWTYPE_CT              "CT"  /* conference total */
+#define GST_SDP_BWTYPE_AS              "AS"  /* application specific */
+#define GST_SDP_BWTYPE_EXT_PREFIX      "X-"  /* extension prefix */
+
+typedef struct {
+  gchar *bwtype;
+  gint   bandwidth;
+} GstSDPBandwidth;
+
+typedef struct {
+  gchar *start;
+  gchar *stop;
+  gint   n_repeat;
+  gchar **repeat;
+} GstSDPTime;
+
+typedef struct {
+  gchar *time;
+  gchar *typed_time;
+} GstSDPZone;
+
+typedef struct {
+  gchar *type;
+  gchar *data;
+} GstSDPKey;
+
+typedef struct {
+  gchar *key;
+  gchar *value;
+} GstSDPAttribute;
+
+typedef struct {
+  gchar         *media;
+  gint           port;
+  gint           num_ports;
+  gchar         *proto;
+  GArray        *fmts;
+  gchar         *information;
+  GArray        *connections;
+  GArray        *bandwidths;
+  GstSDPKey         key;
+  GArray        *attributes;
+} GstSDPMedia;
+
+typedef struct {
+  gchar         *version;
+  GstSDPOrigin      origin;
+  gchar         *session_name;
+  gchar         *information;
+  gchar         *uri;   
+  GArray        *emails;
+  GArray        *phones;
+  GstSDPConnection  connection;
+  GArray        *bandwidths;
+  GArray        *times;
+  GArray        *zones;
+  GstSDPKey         key;
+  GArray        *attributes;
+  GArray        *medias;
+} GstSDPMessage;
+
+/* Session descriptions */
+GstSDPResult      gst_sdp_message_new                 (GstSDPMessage **msg);
+GstSDPResult      gst_sdp_message_init                (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_uninit              (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_free                (GstSDPMessage *msg);
+
+GstSDPResult      gst_sdp_message_parse_buffer        (guint8 *data, guint size, GstSDPMessage *msg);
+
+GstSDPResult      gst_sdp_message_set_version         (GstSDPMessage *msg, gchar *version);
+gchar*            gst_sdp_message_get_version         (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_set_origin          (GstSDPMessage *msg, gchar *username, gchar *sess_id,
+                                                        gchar *sess_version, gchar *nettype,
+                                                        gchar *addrtype, gchar *addr);
+GstSDPOrigin*     gst_sdp_message_get_origin          (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_set_session_name    (GstSDPMessage *msg, gchar *session_name);
+gchar*            gst_sdp_message_get_session_name    (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_set_information     (GstSDPMessage *msg, gchar *information);
+gchar*            gst_sdp_message_get_information     (GstSDPMessage *msg);
+GstSDPResult      gst_sdp_message_set_uri             (GstSDPMessage *msg, gchar *uri);
+gchar*            gst_sdp_message_get_uri             (GstSDPMessage *msg);
+gint              gst_sdp_message_emails_len          (GstSDPMessage *msg);
+gchar*            gst_sdp_message_get_email           (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_email           (GstSDPMessage *msg, gchar *email);
+gint              gst_sdp_message_phones_len          (GstSDPMessage *msg);
+gchar*            gst_sdp_message_get_phone           (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_phone           (GstSDPMessage *msg, gchar *phone);
+GstSDPResult      gst_sdp_message_set_connection      (GstSDPMessage *msg, gchar *nettype, gchar *addrtype,
+                                                       gchar *address, gint ttl, gint addr_number);
+GstSDPConnection* gst_sdp_message_get_connection       (GstSDPMessage *msg);
+gint              gst_sdp_message_bandwidths_len      (GstSDPMessage *msg);
+GstSDPBandwidth*  gst_sdp_message_get_bandwidth       (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_bandwidth       (GstSDPMessage *msg, gchar *bwtype, gint bandwidth);
+gint              gst_sdp_message_times_len           (GstSDPMessage *msg);
+GstSDPTime*       gst_sdp_message_get_time            (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_time            (GstSDPMessage *msg, gchar *time);
+gint              gst_sdp_message_zones_len           (GstSDPMessage *msg);
+GstSDPZone*       gst_sdp_message_get_zone            (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_zone            (GstSDPMessage *msg, gchar *time, gchar *typed_time);
+GstSDPResult      gst_sdp_message_set_key             (GstSDPMessage *msg, gchar *type, gchar *data);
+GstSDPKey*        gst_sdp_message_get_key             (GstSDPMessage *msg);
+gint              gst_sdp_message_attributes_len      (GstSDPMessage *msg);
+GstSDPAttribute*  gst_sdp_message_get_attribute       (GstSDPMessage *msg, guint idx);
+gchar*            gst_sdp_message_get_attribute_val   (GstSDPMessage *msg, gchar *key);
+gchar*            gst_sdp_message_get_attribute_val_n (GstSDPMessage *msg, gchar *key, guint nth);
+GstSDPResult      gst_sdp_message_add_attribute       (GstSDPMessage *msg, gchar *key, gchar *value);
+gint              gst_sdp_message_medias_len          (GstSDPMessage *msg);
+GstSDPMedia*      gst_sdp_message_get_media           (GstSDPMessage *msg, guint idx);
+GstSDPResult      gst_sdp_message_add_media           (GstSDPMessage *msg, GstSDPMedia *media);
+
+
+GstSDPResult      gst_sdp_message_dump                (GstSDPMessage *msg);
+
+/* Media descriptions */
+GstSDPResult      gst_sdp_media_new                   (GstSDPMedia **media);
+GstSDPResult      gst_sdp_media_init                  (GstSDPMedia *media);
+GstSDPResult      gst_sdp_media_uninit                (GstSDPMedia *media);
+GstSDPResult      gst_sdp_media_free                  (GstSDPMedia *media);
+
+GstSDPResult      gst_sdp_media_add_bandwidth         (GstSDPMedia * media, gchar * bwtype, gint bandwidth);
+
+GstSDPResult      gst_sdp_media_add_attribute         (GstSDPMedia *media, gchar * key, gchar * value);
+GstSDPAttribute * gst_sdp_media_get_attribute         (GstSDPMedia *media, guint idx);
+gchar*            gst_sdp_media_get_attribute_val     (GstSDPMedia *media, gchar *key);
+gchar*            gst_sdp_media_get_attribute_val_n   (GstSDPMedia *media, gchar *key, guint nth);
+
+GstSDPResult      gst_sdp_media_add_format            (GstSDPMedia * media, gchar * format);
+gchar*            gst_sdp_media_get_format            (GstSDPMedia *media, guint idx);
+
+G_END_DECLS
+
+#endif /* __GST_SDP_MESSAGE_H__ */
index 2f098f6..2431d4e 100644 (file)
@@ -9,7 +9,7 @@ Description: Streaming media framework, base plugins libraries, uninstalled
 Version: @VERSION@
 Requires: gstreamer-@GST_MAJORMINOR@
 
-Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/tag -L${libdir}/pbutils -L${libdir}/video
+Libs: -L${libdir}/audio -L${libdir}/cdda -L${libdir}/floatcast -L${libdir}/interfaces -L${libdir}/netbuffer -L${libdir}/riff -L${libdir}/rtp -L${libdir}/rtsp -L${libdir}/sdp -L${libdir}/tag -L${libdir}/pbutils -L${libdir}/video
 Cflags: -I${includedir}
 
 libraries=audio cdda floatcast interfaces netbuffer riff tag pbutils video