mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-01-26 17:18:15 +00:00
Ported to 0.9.
Original commit message from CVS: Ported to 0.9. Set up transports, init UDP ports, init RTP session managers.
This commit is contained in:
parent
6cacd6f649
commit
6f0ea35883
23 changed files with 3877 additions and 0 deletions
63
ChangeLog
63
ChangeLog
|
@ -1,3 +1,66 @@
|
|||
2005-05-11 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/rtsp/.cvsignore:
|
||||
* gst/rtsp/Makefile.am:
|
||||
* gst/rtsp/gstrtsp.c: (plugin_init):
|
||||
* gst/rtsp/gstrtsp.h:
|
||||
* gst/rtsp/gstrtspsrc.c: (gst_rtsp_proto_get_type),
|
||||
(gst_rtspsrc_get_type), (gst_rtspsrc_base_init),
|
||||
(gst_rtspsrc_class_init), (gst_rtspsrc_init),
|
||||
(gst_rtspsrc_set_property), (gst_rtspsrc_get_property),
|
||||
(gst_rtspsrc_create_stream), (rtspsrc_add_element),
|
||||
(gst_rtspsrc_stream_setup_rtp),
|
||||
(gst_rtspsrc_stream_configure_transport), (find_stream),
|
||||
(gst_rtspsrc_loop), (gst_rtspsrc_send), (gst_rtspsrc_open),
|
||||
(gst_rtspsrc_close), (gst_rtspsrc_play), (gst_rtspsrc_pause),
|
||||
(gst_rtspsrc_activate), (gst_rtspsrc_change_state):
|
||||
* gst/rtsp/gstrtspsrc.h:
|
||||
* gst/rtsp/rtsp.h:
|
||||
* gst/rtsp/rtspconnection.c: (rtsp_connection_open),
|
||||
(rtsp_connection_create), (append_header), (rtsp_connection_send),
|
||||
(read_line), (read_string), (read_key), (parse_response_status),
|
||||
(parse_line), (read_body), (rtsp_connection_receive),
|
||||
(rtsp_connection_close):
|
||||
* gst/rtsp/rtspconnection.h:
|
||||
* gst/rtsp/rtspdefs.c: (rtsp_init_status), (rtsp_method_as_text),
|
||||
(rtsp_header_as_text), (rtsp_status_as_text),
|
||||
(rtsp_status_to_string), (rtsp_find_header_field):
|
||||
* gst/rtsp/rtspdefs.h:
|
||||
* gst/rtsp/rtspmessage.c: (rtsp_message_new_request),
|
||||
(rtsp_message_init_request), (rtsp_message_new_response),
|
||||
(rtsp_message_init_response), (rtsp_message_init_data),
|
||||
(rtsp_message_add_header), (rtsp_message_remove_header),
|
||||
(rtsp_message_get_header), (rtsp_message_get_header_copy),
|
||||
(rtsp_message_set_body), (rtsp_message_set_body_copy),
|
||||
(rtsp_message_get_body), (rtsp_message_get_body_copy), (dump_mem),
|
||||
(dump_key_value), (rtsp_message_dump):
|
||||
* gst/rtsp/rtspmessage.h:
|
||||
* gst/rtsp/rtspstream.h:
|
||||
* gst/rtsp/rtsptransport.c: (rtsp_transport_new),
|
||||
(rtsp_transport_init), (parse_mode), (parse_range),
|
||||
(rtsp_transport_parse), (rtsp_transport_free):
|
||||
* gst/rtsp/rtsptransport.h:
|
||||
* gst/rtsp/rtspurl.c: (rtsp_url_parse), (rtsp_url_free):
|
||||
* gst/rtsp/rtspurl.h:
|
||||
* gst/rtsp/sdp.h:
|
||||
* gst/rtsp/sdpmessage.c: (sdp_message_new), (sdp_message_init),
|
||||
(sdp_message_clean), (sdp_message_free), (sdp_media_new),
|
||||
(sdp_media_init), (sdp_message_set_origin),
|
||||
(sdp_message_get_origin), (sdp_message_set_connection),
|
||||
(sdp_message_get_connection), (sdp_message_add_bandwidth),
|
||||
(sdp_message_add_time), (sdp_message_add_zone),
|
||||
(sdp_message_set_key), (sdp_message_get_key),
|
||||
(sdp_message_get_attribute_val), (sdp_message_add_attribute),
|
||||
(sdp_message_add_media), (sdp_media_add_attribute),
|
||||
(sdp_media_add_bandwidth), (sdp_media_add_format),
|
||||
(sdp_media_get_attribute_val), (read_string), (read_string_del),
|
||||
(sdp_parse_line), (sdp_message_parse_buffer), (print_media),
|
||||
(sdp_message_dump):
|
||||
* gst/rtsp/sdpmessage.h:
|
||||
* gst/rtsp/test.c: (main):
|
||||
Ported to 0.9.
|
||||
Set up transports, init UDP ports, init RTP session managers.
|
||||
|
||||
2005-05-11 Wim Taymans <wim@fluendo.com>
|
||||
|
||||
* gst/rtp/Makefile.am:
|
||||
|
|
8
gst/rtsp/.gitignore
vendored
Normal file
8
gst/rtsp/.gitignore
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
Makefile
|
||||
Makefile.in
|
||||
*.o
|
||||
*.lo
|
||||
*.la
|
||||
.deps
|
||||
.libs
|
||||
test
|
22
gst/rtsp/Makefile.am
Normal file
22
gst/rtsp/Makefile.am
Normal file
|
@ -0,0 +1,22 @@
|
|||
|
||||
plugin_LTLIBRARIES = libgstrtsp.la
|
||||
|
||||
libgstrtsp_la_SOURCES = gstrtsp.c gstrtspsrc.c \
|
||||
rtspconnection.c \
|
||||
rtspdefs.c \
|
||||
rtspmessage.c \
|
||||
rtsptransport.c \
|
||||
rtspurl.c \
|
||||
sdpmessage.c
|
||||
|
||||
libgstrtsp_la_CFLAGS = $(GST_CFLAGS)
|
||||
libgstrtsp_la_LIBADD =
|
||||
libgstrtsp_la_LDFLAGS = $(GST_PLUGIN_LDFLAGS)
|
||||
|
||||
check_PROGRAMS = test
|
||||
|
||||
test_SOURCES = test.c rtspdefs.c rtspurl.c rtspconnection.c rtspmessage.c rtsptransport.c sdpmessage.c
|
||||
test_CFLAGS = $(GST_CFLAGS)
|
||||
test_LDFLAGS = $(GST_LIBS)
|
||||
|
||||
noinst_HEADERS = gstrtspsrc.h gstrtsp.h rtsptransport.h
|
40
gst/rtsp/gstrtsp.c
Normal file
40
gst/rtsp/gstrtsp.c
Normal file
|
@ -0,0 +1,40 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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 "gstrtspsrc.h"
|
||||
|
||||
static gboolean
|
||||
plugin_init (GstPlugin * plugin)
|
||||
{
|
||||
if (!gst_element_register (plugin, "rtspsrc", GST_RANK_NONE,
|
||||
GST_TYPE_RTSPSRC))
|
||||
return FALSE;
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
GST_PLUGIN_DEFINE (GST_VERSION_MAJOR,
|
||||
GST_VERSION_MINOR,
|
||||
"rtsp",
|
||||
"transfer data via RTSP",
|
||||
plugin_init, VERSION, GST_LICENSE, GST_PACKAGE, GST_ORIGIN)
|
30
gst/rtsp/gstrtsp.h
Normal file
30
gst/rtsp/gstrtsp.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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 __GST_RTSP_H__
|
||||
#define __GST_RTSP_H__
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __GST_RTSP_H__ */
|
||||
|
868
gst/rtsp/gstrtspsrc.c
Normal file
868
gst/rtsp/gstrtspsrc.c
Normal file
|
@ -0,0 +1,868 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "gstrtspsrc.h"
|
||||
#include "sdp.h"
|
||||
|
||||
/* elementfactory information */
|
||||
static GstElementDetails gst_rtspsrc_details =
|
||||
GST_ELEMENT_DETAILS ("RTSP packet receiver",
|
||||
"Source/Network",
|
||||
"Receive data over the network via RTSP",
|
||||
"Wim Taymans <wim@fluendo.com>");
|
||||
|
||||
static GstStaticPadTemplate rtptemplate =
|
||||
GST_STATIC_PAD_TEMPLATE ("rtp_stream%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
static GstStaticPadTemplate rtcptemplate =
|
||||
GST_STATIC_PAD_TEMPLATE ("rtcp_stream%d",
|
||||
GST_PAD_SRC,
|
||||
GST_PAD_SOMETIMES,
|
||||
GST_STATIC_CAPS_ANY);
|
||||
|
||||
enum
|
||||
{
|
||||
/* FILL ME */
|
||||
LAST_SIGNAL
|
||||
};
|
||||
|
||||
#define DEFAULT_LOCATION NULL
|
||||
#define DEFAULT_PROTOCOLS GST_RTSP_PROTO_UDP_UNICAST | GST_RTSP_PROTO_UDP_MULTICAST | GST_RTSP_PROTO_TCP
|
||||
#define DEFAULT_DEBUG FALSE
|
||||
|
||||
enum
|
||||
{
|
||||
PROP_0,
|
||||
PROP_LOCATION,
|
||||
PROP_PROTOCOLS,
|
||||
PROP_DEBUG,
|
||||
/* FILL ME */
|
||||
};
|
||||
|
||||
#define GST_TYPE_RTSP_PROTO (gst_rtsp_proto_get_type())
|
||||
static GType
|
||||
gst_rtsp_proto_get_type (void)
|
||||
{
|
||||
static GType rtsp_proto_type = 0;
|
||||
static GFlagsValue rtsp_proto[] = {
|
||||
{GST_RTSP_PROTO_UDP_UNICAST, "UDP Unicast", "UDP unicast mode"},
|
||||
{GST_RTSP_PROTO_UDP_MULTICAST, "UDP Multicast", "UDP Multicast mode"},
|
||||
{GST_RTSP_PROTO_TCP, "TCP", "TCP interleaved mode"},
|
||||
{0, NULL, NULL},
|
||||
};
|
||||
|
||||
if (!rtsp_proto_type) {
|
||||
rtsp_proto_type = g_flags_register_static ("GstRTSPProto", rtsp_proto);
|
||||
}
|
||||
return rtsp_proto_type;
|
||||
}
|
||||
|
||||
|
||||
static void gst_rtspsrc_base_init (gpointer g_class);
|
||||
static void gst_rtspsrc_class_init (GstRTSPSrc * klass);
|
||||
static void gst_rtspsrc_init (GstRTSPSrc * rtspsrc);
|
||||
|
||||
static GstElementStateReturn gst_rtspsrc_change_state (GstElement * element);
|
||||
static gboolean gst_rtspsrc_activate (GstPad * pad, GstActivateMode mode);
|
||||
|
||||
static void gst_rtspsrc_set_property (GObject * object, guint prop_id,
|
||||
const GValue * value, GParamSpec * pspec);
|
||||
static void gst_rtspsrc_get_property (GObject * object, guint prop_id,
|
||||
GValue * value, GParamSpec * pspec);
|
||||
|
||||
static void gst_rtspsrc_loop (GstRTSPSrc * src);
|
||||
|
||||
static GstElementClass *parent_class = NULL;
|
||||
|
||||
/*static guint gst_rtspsrc_signals[LAST_SIGNAL] = { 0 }; */
|
||||
|
||||
GType
|
||||
gst_rtspsrc_get_type (void)
|
||||
{
|
||||
static GType rtspsrc_type = 0;
|
||||
|
||||
if (!rtspsrc_type) {
|
||||
static const GTypeInfo rtspsrc_info = {
|
||||
sizeof (GstRTSPSrcClass),
|
||||
gst_rtspsrc_base_init,
|
||||
NULL,
|
||||
(GClassInitFunc) gst_rtspsrc_class_init,
|
||||
NULL,
|
||||
NULL,
|
||||
sizeof (GstRTSPSrc),
|
||||
0,
|
||||
(GInstanceInitFunc) gst_rtspsrc_init,
|
||||
NULL
|
||||
};
|
||||
|
||||
rtspsrc_type =
|
||||
g_type_register_static (GST_TYPE_ELEMENT, "GstRTSPSrc", &rtspsrc_info,
|
||||
0);
|
||||
}
|
||||
return rtspsrc_type;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_base_init (gpointer g_class)
|
||||
{
|
||||
GstElementClass *element_class = GST_ELEMENT_CLASS (g_class);
|
||||
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&rtptemplate));
|
||||
gst_element_class_add_pad_template (element_class,
|
||||
gst_static_pad_template_get (&rtcptemplate));
|
||||
|
||||
gst_element_class_set_details (element_class, &gst_rtspsrc_details);
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_class_init (GstRTSPSrc * klass)
|
||||
{
|
||||
GObjectClass *gobject_class;
|
||||
GstElementClass *gstelement_class;
|
||||
|
||||
gobject_class = (GObjectClass *) klass;
|
||||
gstelement_class = (GstElementClass *) klass;
|
||||
|
||||
parent_class = g_type_class_ref (GST_TYPE_ELEMENT);
|
||||
|
||||
gobject_class->set_property = gst_rtspsrc_set_property;
|
||||
gobject_class->get_property = gst_rtspsrc_get_property;
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_LOCATION,
|
||||
g_param_spec_string ("location", "RTSP Location",
|
||||
"Location of the RTSP url to read",
|
||||
DEFAULT_LOCATION, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_PROTOCOLS,
|
||||
g_param_spec_flags ("protocols", "Protocols", "Allowed protocols",
|
||||
GST_TYPE_RTSP_PROTO, DEFAULT_PROTOCOLS,
|
||||
G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
g_object_class_install_property (G_OBJECT_CLASS (klass), PROP_DEBUG,
|
||||
g_param_spec_boolean ("debug", "Debug",
|
||||
"Dump request qnd response messages to stdout",
|
||||
DEFAULT_DEBUG, G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
|
||||
|
||||
gstelement_class->change_state = gst_rtspsrc_change_state;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_init (GstRTSPSrc * src)
|
||||
{
|
||||
/*
|
||||
src->srcpad =
|
||||
gst_pad_new_from_template (gst_static_pad_template_get (&srctemplate),
|
||||
"src");
|
||||
gst_pad_set_loop_function (src->srcpad, gst_rtspsrc_loop);
|
||||
gst_pad_set_activate_function (src->srcpad, gst_rtspsrc_activate);
|
||||
gst_element_add_pad (GST_ELEMENT (src), src->srcpad);
|
||||
*/
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_set_property (GObject * object, guint prop_id, const GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstRTSPSrc *rtspsrc;
|
||||
|
||||
rtspsrc = GST_RTSPSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LOCATION:
|
||||
g_free (rtspsrc->location);
|
||||
rtspsrc->location = g_value_dup_string (value);
|
||||
break;
|
||||
case PROP_PROTOCOLS:
|
||||
rtspsrc->protocols = g_value_get_flags (value);
|
||||
break;
|
||||
case PROP_DEBUG:
|
||||
rtspsrc->debug = g_value_get_boolean (value);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_get_property (GObject * object, guint prop_id, GValue * value,
|
||||
GParamSpec * pspec)
|
||||
{
|
||||
GstRTSPSrc *rtspsrc;
|
||||
|
||||
rtspsrc = GST_RTSPSRC (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_LOCATION:
|
||||
g_value_set_string (value, rtspsrc->location);
|
||||
break;
|
||||
case PROP_PROTOCOLS:
|
||||
g_value_set_flags (value, rtspsrc->protocols);
|
||||
break;
|
||||
case PROP_DEBUG:
|
||||
g_value_set_boolean (value, rtspsrc->debug);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static GstRTSPStream *
|
||||
gst_rtspsrc_create_stream (GstRTSPSrc * src)
|
||||
{
|
||||
GstRTSPStream *s;
|
||||
|
||||
s = g_new0 (GstRTSPStream, 1);
|
||||
s->parent = src;
|
||||
|
||||
src->streams = g_list_append (src->streams, s);
|
||||
|
||||
return s;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rtspsrc_add_element (GstRTSPSrc * src, GstElement * element)
|
||||
{
|
||||
gst_object_set_parent (GST_OBJECT (element), GST_OBJECT (src));
|
||||
gst_element_set_manager (element, GST_ELEMENT_MANAGER (src));
|
||||
gst_element_set_scheduler (element, GST_ELEMENT_SCHEDULER (src));
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_stream_setup_rtp (GstRTSPStream * stream, gint * rtpport,
|
||||
gint * rtcpport)
|
||||
{
|
||||
GstElement *rtpsrc;
|
||||
GstElementStateReturn ret;
|
||||
GstRTSPSrc *src;
|
||||
|
||||
src = stream->parent;
|
||||
|
||||
if (!(stream->rtpsrc =
|
||||
gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL)))
|
||||
goto no_udp_rtp_protocol;
|
||||
|
||||
/* we manage this element */
|
||||
rtspsrc_add_element (src, stream->rtpsrc);
|
||||
|
||||
if ((ret =
|
||||
gst_element_set_state (stream->rtpsrc,
|
||||
GST_STATE_PAUSED)) != GST_STATE_SUCCESS)
|
||||
goto start_rtp_failure;
|
||||
|
||||
if (!(stream->rtcpsrc =
|
||||
gst_element_make_from_uri (GST_URI_SRC, "udp://0.0.0.0:0", NULL)))
|
||||
goto no_udp_rtcp_protocol;
|
||||
|
||||
/* we manage this element */
|
||||
rtspsrc_add_element (src, stream->rtcpsrc);
|
||||
|
||||
if ((ret =
|
||||
gst_element_set_state (stream->rtcpsrc,
|
||||
GST_STATE_PAUSED)) != GST_STATE_SUCCESS)
|
||||
goto start_rtcp_failure;
|
||||
|
||||
g_object_get (G_OBJECT (stream->rtpsrc), "port", rtpport, NULL);
|
||||
g_object_get (G_OBJECT (stream->rtcpsrc), "port", rtcpport, NULL);
|
||||
|
||||
return TRUE;
|
||||
|
||||
/* ERRORS, FIXME, cleanup */
|
||||
no_udp_rtp_protocol:
|
||||
{
|
||||
GST_DEBUG ("could not get UDP source for rtp");
|
||||
return FALSE;
|
||||
}
|
||||
no_udp_rtcp_protocol:
|
||||
{
|
||||
GST_DEBUG ("could not get UDP source for rtcp");
|
||||
return FALSE;
|
||||
}
|
||||
start_rtp_failure:
|
||||
{
|
||||
GST_DEBUG ("could not start UDP source for rtp");
|
||||
return FALSE;
|
||||
}
|
||||
start_rtcp_failure:
|
||||
{
|
||||
GST_DEBUG ("could not start UDP source for rtcp");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||
RTSPTransport * transport)
|
||||
{
|
||||
GstRTSPSrc *src;
|
||||
|
||||
src = stream->parent;
|
||||
|
||||
if (transport->lower_transport == RTSP_LOWER_TRANS_TCP) {
|
||||
GstPad *pad;
|
||||
|
||||
/* configure for interleaved delivery */
|
||||
if (!(stream->rtpdec = gst_element_factory_make ("rtpdec", NULL)))
|
||||
goto no_element;
|
||||
|
||||
/* we manage this element */
|
||||
rtspsrc_add_element (src, stream->rtpdec);
|
||||
stream->rtpdecrtp = gst_element_get_pad (stream->rtpdec, "sinkrtp");
|
||||
stream->rtpdecrtcp = gst_element_get_pad (stream->rtpdec, "sinkrtcp");
|
||||
|
||||
/* FIXME, make sure it outputs the caps */
|
||||
pad = gst_element_get_pad (stream->rtpdec, "srcrtp");
|
||||
gst_element_add_ghost_pad (GST_ELEMENT (src), pad, "srcrtp");
|
||||
gst_object_unref (GST_OBJECT (pad));
|
||||
} else {
|
||||
/* configure for UDP delivery, FIXME */
|
||||
}
|
||||
return TRUE;
|
||||
|
||||
no_element:
|
||||
{
|
||||
GST_DEBUG ("no rtpdec element found");
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gint
|
||||
find_stream (GstRTSPStream * stream, gconstpointer a)
|
||||
{
|
||||
gint channel = GPOINTER_TO_INT (a);
|
||||
|
||||
if (stream->rtpchannel == channel || stream->rtcpchannel == channel)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void
|
||||
gst_rtspsrc_loop (GstRTSPSrc * src)
|
||||
{
|
||||
RTSPMessage response = { 0 };
|
||||
RTSPResult res;
|
||||
gint channel;
|
||||
GList *lstream;
|
||||
GstRTSPStream *stream;
|
||||
GstPadChainFunction chainfunc;
|
||||
GstPad *outpad;
|
||||
guint8 *data;
|
||||
gint size;
|
||||
|
||||
do {
|
||||
GST_DEBUG ("doing reveive");
|
||||
if ((res = rtsp_connection_receive (src->connection, &response)) < 0)
|
||||
goto receive_error;
|
||||
GST_DEBUG ("got packet");
|
||||
}
|
||||
while (response.type != RTSP_MESSAGE_DATA);
|
||||
|
||||
channel = response.type_data.data.channel;
|
||||
|
||||
lstream = g_list_find_custom (src->streams, GINT_TO_POINTER (channel),
|
||||
(GCompareFunc) find_stream);
|
||||
if (!lstream)
|
||||
goto unknown_stream;
|
||||
|
||||
stream = (GstRTSPStream *) lstream->data;
|
||||
if (channel == stream->rtpchannel)
|
||||
outpad = stream->rtpdecrtp;
|
||||
else if (channel == stream->rtcpchannel)
|
||||
outpad = stream->rtpdecrtcp;
|
||||
|
||||
rtsp_message_get_body (&response, &data, &size);
|
||||
|
||||
/* channels are not correct on some servers, do extra check */
|
||||
if (data[1] >= 200 && data[1] <= 204) {
|
||||
/* hmm RTCP message */
|
||||
outpad = stream->rtpdecrtcp;
|
||||
}
|
||||
|
||||
if ((chainfunc = GST_RPAD_CHAINFUNC (outpad))) {
|
||||
GstBuffer *buf;
|
||||
|
||||
buf = gst_buffer_new_and_alloc (size);
|
||||
memcpy (GST_BUFFER_DATA (buf), data, size);
|
||||
|
||||
if (chainfunc (outpad, buf) != GST_FLOW_OK)
|
||||
goto need_pause;
|
||||
}
|
||||
|
||||
unknown_stream:
|
||||
|
||||
return;
|
||||
|
||||
receive_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not receive message."), (NULL));
|
||||
/*
|
||||
gst_pad_push_event (src->srcpad, gst_event_new (GST_EVENT_EOS));
|
||||
*/
|
||||
goto need_pause;
|
||||
}
|
||||
need_pause:
|
||||
{
|
||||
gst_task_pause (src->task);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_send (GstRTSPSrc * src, RTSPMessage * request,
|
||||
RTSPMessage * response)
|
||||
{
|
||||
RTSPResult res;
|
||||
|
||||
if (src->debug) {
|
||||
rtsp_message_dump (request);
|
||||
}
|
||||
if ((res = rtsp_connection_send (src->connection, request)) < 0)
|
||||
goto send_error;
|
||||
|
||||
if ((res = rtsp_connection_receive (src->connection, response)) < 0)
|
||||
goto receive_error;
|
||||
if (response->type_data.response.code != RTSP_STS_OK)
|
||||
goto error_response;
|
||||
|
||||
if (src->debug) {
|
||||
rtsp_message_dump (response);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
receive_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ,
|
||||
("Could not receive message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
error_response:
|
||||
{
|
||||
rtsp_message_dump (request);
|
||||
rtsp_message_dump (response);
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, ("Got error response."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_open (GstRTSPSrc * src)
|
||||
{
|
||||
RTSPUrl *url;
|
||||
RTSPResult res;
|
||||
RTSPMessage request = { 0 };
|
||||
RTSPMessage response = { 0 };
|
||||
guint8 *data;
|
||||
guint size;
|
||||
SDPMessage sdp = { 0 };
|
||||
GstRTSPProto protocols;
|
||||
|
||||
/* parse url */
|
||||
GST_DEBUG ("parsing url...");
|
||||
if ((res = rtsp_url_parse (src->location, &url)) < 0)
|
||||
goto invalid_url;
|
||||
|
||||
/* open connection */
|
||||
GST_DEBUG ("opening connection...");
|
||||
if ((res = rtsp_connection_open (url, &src->connection)) < 0)
|
||||
goto could_not_open;
|
||||
|
||||
/* create DESCRIBE */
|
||||
GST_DEBUG ("create describe...");
|
||||
if ((res =
|
||||
rtsp_message_init_request (RTSP_DESCRIBE, src->location,
|
||||
&request)) < 0)
|
||||
goto create_request_failed;
|
||||
/* we accept SDP for now */
|
||||
rtsp_message_add_header (&request, RTSP_HDR_ACCEPT, "application/sdp");
|
||||
|
||||
/* send DESCRIBE */
|
||||
GST_DEBUG ("send describe...");
|
||||
if (!gst_rtspsrc_send (src, &request, &response))
|
||||
goto send_error;
|
||||
|
||||
/* parse SDP */
|
||||
rtsp_message_get_body (&response, &data, &size);
|
||||
|
||||
GST_DEBUG ("parse sdp...");
|
||||
sdp_message_init (&sdp);
|
||||
sdp_message_parse_buffer (data, size, &sdp);
|
||||
|
||||
/* we allow all configured protocols */
|
||||
protocols = src->protocols;
|
||||
/* setup streams */
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < sdp_message_medias_len (&sdp); i++) {
|
||||
SDPMedia *media;
|
||||
gchar *setup_url;
|
||||
gchar *control_url;
|
||||
gchar *transports;
|
||||
GstRTSPStream *stream;
|
||||
|
||||
media = sdp_message_get_media (&sdp, i);
|
||||
|
||||
stream = gst_rtspsrc_create_stream (src);
|
||||
|
||||
GST_DEBUG ("setup media %d", i);
|
||||
control_url = sdp_media_get_attribute_val (media, "control");
|
||||
if (control_url == NULL) {
|
||||
GST_DEBUG ("no control url found, skipping stream");
|
||||
continue;
|
||||
}
|
||||
|
||||
/* FIXME, check absolute/relative URL */
|
||||
setup_url = g_strdup_printf ("%s/%s", src->location, control_url);
|
||||
|
||||
GST_DEBUG ("setup %s", setup_url);
|
||||
/* create SETUP request */
|
||||
if ((res =
|
||||
rtsp_message_init_request (RTSP_SETUP, setup_url,
|
||||
&request)) < 0) {
|
||||
g_free (setup_url);
|
||||
goto create_request_failed;
|
||||
}
|
||||
g_free (setup_url);
|
||||
|
||||
|
||||
transports = g_strdup ("");
|
||||
if (protocols & GST_RTSP_PROTO_UDP_UNICAST) {
|
||||
gchar *new;
|
||||
gint rtpport, rtcpport;
|
||||
gchar *trxparams;
|
||||
|
||||
/* allocate two udp ports */
|
||||
gst_rtspsrc_stream_setup_rtp (stream, &rtpport, &rtcpport);
|
||||
|
||||
trxparams = g_strdup_printf ("client_port=%d-%d", rtpport, rtcpport);
|
||||
new = g_strconcat (transports, "RTP/AVP/UDP;unicast;", trxparams, NULL);
|
||||
g_free (trxparams);
|
||||
g_free (transports);
|
||||
transports = new;
|
||||
}
|
||||
if (protocols & GST_RTSP_PROTO_UDP_MULTICAST) {
|
||||
gchar *new;
|
||||
|
||||
new =
|
||||
g_strconcat (transports, transports[0] ? "," : "",
|
||||
",RTP/AVP/UDP;multicast", NULL);
|
||||
g_free (transports);
|
||||
transports = new;
|
||||
}
|
||||
if (protocols & GST_RTSP_PROTO_TCP) {
|
||||
gchar *new;
|
||||
|
||||
new =
|
||||
g_strconcat (transports, transports[0] ? "," : "", ",RTP/AVP/TCP",
|
||||
NULL);
|
||||
g_free (transports);
|
||||
transports = new;
|
||||
}
|
||||
|
||||
/* select transport, copy is made when adding to header */
|
||||
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
|
||||
g_free (transports);
|
||||
|
||||
rtsp_message_dump (&request);
|
||||
|
||||
if (!gst_rtspsrc_send (src, &request, &response))
|
||||
goto send_error;
|
||||
|
||||
/* parse response transport */
|
||||
{
|
||||
gchar *resptrans;
|
||||
RTSPTransport transport = { 0 };
|
||||
|
||||
rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
|
||||
|
||||
/* update allowed transports for other streams */
|
||||
rtsp_transport_parse (resptrans, &transport);
|
||||
if (transport.lower_transport == RTSP_LOWER_TRANS_TCP) {
|
||||
protocols = GST_RTSP_PROTO_TCP;
|
||||
src->interleaved = TRUE;
|
||||
} else {
|
||||
if (transport.multicast) {
|
||||
/* disable unicast */
|
||||
protocols = GST_RTSP_PROTO_UDP_MULTICAST;
|
||||
} else {
|
||||
/* disable multicast */
|
||||
protocols = GST_RTSP_PROTO_UDP_UNICAST;
|
||||
}
|
||||
}
|
||||
gst_rtspsrc_stream_configure_transport (stream, &transport);
|
||||
rtsp_transport_init (&transport);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
invalid_url:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, NOT_FOUND,
|
||||
("Not a valid RTSP url."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
could_not_open:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, OPEN_READ_WRITE,
|
||||
("Could not open connection."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
create_request_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
("Could not create request."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_close (GstRTSPSrc * src)
|
||||
{
|
||||
RTSPMessage request = { 0 };
|
||||
RTSPMessage response = { 0 };
|
||||
RTSPResult res;
|
||||
|
||||
GST_DEBUG ("TEARDOWN...");
|
||||
/* do TEARDOWN */
|
||||
if ((res =
|
||||
rtsp_message_init_request (RTSP_TEARDOWN, src->location,
|
||||
&request)) < 0)
|
||||
goto create_request_failed;
|
||||
|
||||
if (!gst_rtspsrc_send (src, &request, &response))
|
||||
goto send_error;
|
||||
|
||||
/* close connection */
|
||||
GST_DEBUG ("closing connection...");
|
||||
if ((res = rtsp_connection_close (src->connection)) < 0)
|
||||
goto close_failed;
|
||||
|
||||
return TRUE;
|
||||
|
||||
create_request_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
("Could not create request."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
close_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, CLOSE, ("Close failed."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_play (GstRTSPSrc * src)
|
||||
{
|
||||
RTSPMessage request = { 0 };
|
||||
RTSPMessage response = { 0 };
|
||||
RTSPResult res;
|
||||
|
||||
GST_DEBUG ("PLAY...");
|
||||
/* do play */
|
||||
if ((res =
|
||||
rtsp_message_init_request (RTSP_PLAY, src->location, &request)) < 0)
|
||||
goto create_request_failed;
|
||||
|
||||
if (!gst_rtspsrc_send (src, &request, &response))
|
||||
goto send_error;
|
||||
|
||||
if (GST_ELEMENT_SCHEDULER (src) && src->interleaved) {
|
||||
src->task =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (src),
|
||||
(GstTaskFunction) gst_rtspsrc_loop, src);
|
||||
|
||||
gst_task_start (src->task);
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
||||
create_request_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
("Could not create request."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_pause (GstRTSPSrc * src)
|
||||
{
|
||||
RTSPMessage request = { 0 };
|
||||
RTSPMessage response = { 0 };
|
||||
RTSPResult res;
|
||||
|
||||
GST_DEBUG ("PAUSE...");
|
||||
/* do pause */
|
||||
if ((res =
|
||||
rtsp_message_init_request (RTSP_PAUSE, src->location, &request)) < 0)
|
||||
goto create_request_failed;
|
||||
|
||||
if (!gst_rtspsrc_send (src, &request, &response))
|
||||
goto send_error;
|
||||
|
||||
return TRUE;
|
||||
|
||||
create_request_failed:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, LIBRARY, INIT,
|
||||
("Could not create request."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
send_error:
|
||||
{
|
||||
GST_ELEMENT_ERROR (src, RESOURCE, WRITE,
|
||||
("Could not send message."), (NULL));
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_activate (GstPad * pad, GstActivateMode mode)
|
||||
{
|
||||
gboolean result;
|
||||
GstRTSPSrc *rtspsrc;
|
||||
|
||||
rtspsrc = GST_RTSPSRC (GST_OBJECT_PARENT (pad));
|
||||
|
||||
switch (mode) {
|
||||
case GST_ACTIVATE_PUSH:
|
||||
/* if we have a scheduler we can start the task */
|
||||
if (GST_ELEMENT_SCHEDULER (rtspsrc) && rtspsrc->interleaved) {
|
||||
GST_STREAM_LOCK (pad);
|
||||
GST_RPAD_TASK (pad) =
|
||||
gst_scheduler_create_task (GST_ELEMENT_SCHEDULER (rtspsrc),
|
||||
(GstTaskFunction) gst_rtspsrc_loop, pad);
|
||||
|
||||
gst_task_start (GST_RPAD_TASK (pad));
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
result = TRUE;
|
||||
}
|
||||
break;
|
||||
case GST_ACTIVATE_PULL:
|
||||
result = FALSE;
|
||||
break;
|
||||
case GST_ACTIVATE_NONE:
|
||||
/* step 1, unblock clock sync (if any) */
|
||||
|
||||
/* step 2, make sure streaming finishes */
|
||||
GST_STREAM_LOCK (pad);
|
||||
gst_rtspsrc_close (rtspsrc);
|
||||
|
||||
/* step 3, stop the task */
|
||||
if (GST_RPAD_TASK (pad)) {
|
||||
gst_task_stop (GST_RPAD_TASK (pad));
|
||||
gst_object_unref (GST_OBJECT (GST_RPAD_TASK (pad)));
|
||||
GST_RPAD_TASK (pad) = NULL;
|
||||
}
|
||||
GST_STREAM_UNLOCK (pad);
|
||||
|
||||
result = TRUE;
|
||||
break;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static GstElementStateReturn
|
||||
gst_rtspsrc_change_state (GstElement * element)
|
||||
{
|
||||
GstRTSPSrc *rtspsrc;
|
||||
GstElementState transition;
|
||||
GstElementStateReturn ret;
|
||||
|
||||
rtspsrc = GST_RTSPSRC (element);
|
||||
|
||||
transition = GST_STATE_TRANSITION (rtspsrc);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_NULL_TO_READY:
|
||||
break;
|
||||
case GST_STATE_READY_TO_PAUSED:
|
||||
rtspsrc->interleaved = FALSE;
|
||||
gst_rtspsrc_open (rtspsrc);
|
||||
/* need to play now for the preroll, might delay that to
|
||||
* next state when we have NO_PREROLL as a return value */
|
||||
gst_rtspsrc_play (rtspsrc);
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_PLAYING:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
ret = GST_ELEMENT_CLASS (parent_class)->change_state (element);
|
||||
|
||||
switch (transition) {
|
||||
case GST_STATE_PLAYING_TO_PAUSED:
|
||||
break;
|
||||
case GST_STATE_PAUSED_TO_READY:
|
||||
gst_rtspsrc_pause (rtspsrc);
|
||||
break;
|
||||
case GST_STATE_READY_TO_NULL:
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
106
gst/rtsp/gstrtspsrc.h
Normal file
106
gst/rtsp/gstrtspsrc.h
Normal file
|
@ -0,0 +1,106 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <1999> Erik Walthinsen <omega@cse.ogi.edu>
|
||||
*
|
||||
* 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 __GST_RTSPSRC_H__
|
||||
#define __GST_RTSPSRC_H__
|
||||
|
||||
#include <gst/gst.h>
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif /* __cplusplus */
|
||||
|
||||
#include "gstrtsp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
#define GST_TYPE_RTSPSRC \
|
||||
(gst_rtspsrc_get_type())
|
||||
#define GST_RTSPSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTSPSRC,GstRTSPSrc))
|
||||
#define GST_RTSPSRC_CLASS(klass) \
|
||||
(G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTSPSRC,GstRTSPSrc))
|
||||
#define GST_IS_RTSPSRC(obj) \
|
||||
(G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTSPSRC))
|
||||
#define GST_IS_RTSPSRC_CLASS(obj) \
|
||||
(G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTSPSRC))
|
||||
|
||||
typedef struct _GstRTSPSrc GstRTSPSrc;
|
||||
typedef struct _GstRTSPSrcClass GstRTSPSrcClass;
|
||||
|
||||
/* flags with allowed protocols */
|
||||
typedef enum
|
||||
{
|
||||
GST_RTSP_PROTO_UDP_UNICAST = (1 << 0),
|
||||
GST_RTSP_PROTO_UDP_MULTICAST = (1 << 1),
|
||||
GST_RTSP_PROTO_TCP = (1 << 2),
|
||||
} GstRTSPProto;
|
||||
|
||||
typedef struct _GstRTSPStream GstRTSPStream;
|
||||
|
||||
struct _GstRTSPStream {
|
||||
gint rtpchannel;
|
||||
gint rtcpchannel;
|
||||
|
||||
GstRTSPSrc *parent;
|
||||
|
||||
/* our udp sources */
|
||||
GstElement *rtpsrc;
|
||||
GstElement *rtcpsrc;
|
||||
|
||||
/* our udp sink back to the server */
|
||||
GstElement *rtcpsink;
|
||||
|
||||
/* the rtp decoder */
|
||||
GstElement *rtpdec;
|
||||
GstPad *rtpdecrtp;
|
||||
GstPad *rtpdecrtcp;
|
||||
};
|
||||
|
||||
struct _GstRTSPSrc {
|
||||
GstElement element;
|
||||
|
||||
gboolean interleaved;
|
||||
GstTask *task;
|
||||
|
||||
GList *streams;
|
||||
|
||||
gchar *location;
|
||||
gboolean debug;
|
||||
|
||||
GstRTSPProto protocols;
|
||||
|
||||
RTSPConnection *connection;
|
||||
RTSPMessage *request;
|
||||
RTSPMessage *response;
|
||||
};
|
||||
|
||||
struct _GstRTSPSrcClass {
|
||||
GstElementClass parent_class;
|
||||
};
|
||||
|
||||
GType gst_rtspsrc_get_type(void);
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif /* __cplusplus */
|
||||
|
||||
|
||||
#endif /* __GST_RTSPSRC_H__ */
|
30
gst/rtsp/rtsp.h
Normal file
30
gst/rtsp/rtsp.h
Normal file
|
@ -0,0 +1,30 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_H__
|
||||
#define __RTSP_H__
|
||||
|
||||
#include <rtspconnection.h>
|
||||
#include <rtspdefs.h>
|
||||
#include <rtspmessage.h>
|
||||
#include <rtspstream.h>
|
||||
#include <rtsptransport.h>
|
||||
#include <rtspurl.h>
|
||||
|
||||
#endif /* __RTSP_H__ */
|
432
gst/rtsp/rtspconnection.c
Normal file
432
gst/rtsp/rtspconnection.c
Normal file
|
@ -0,0 +1,432 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <netdb.h>
|
||||
#include <stdio.h>
|
||||
#include <unistd.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "rtspconnection.h"
|
||||
|
||||
RTSPResult
|
||||
rtsp_connection_open (RTSPUrl * url, RTSPConnection ** conn)
|
||||
{
|
||||
gint fd;
|
||||
struct sockaddr_in sin;
|
||||
struct hostent *hostinfo;
|
||||
char **addrs;
|
||||
gchar *ip;
|
||||
struct in_addr addr;
|
||||
gint ret;
|
||||
|
||||
if (url == NULL || conn == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
if (url->protocol != RTSP_PROTO_TCP)
|
||||
return RTSP_ENOTIMPL;
|
||||
|
||||
/* 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_ntoa (*(struct in_addr *) *addrs);
|
||||
}
|
||||
|
||||
fd = socket (AF_INET, SOCK_STREAM, 0);
|
||||
if (fd == -1)
|
||||
goto sys_error;
|
||||
|
||||
memset (&sin, 0, sizeof (sin));
|
||||
sin.sin_family = AF_INET; /* network socket */
|
||||
sin.sin_port = htons (url->port); /* on port */
|
||||
sin.sin_addr.s_addr = inet_addr (ip); /* on host ip */
|
||||
|
||||
ret = connect (fd, (struct sockaddr *) &sin, sizeof (sin));
|
||||
if (ret != 0)
|
||||
goto sys_error;
|
||||
|
||||
return rtsp_connection_create (fd, conn);
|
||||
|
||||
sys_error:
|
||||
{
|
||||
return RTSP_ESYS;
|
||||
}
|
||||
not_resolved:
|
||||
{
|
||||
g_warning ("could not resolve host \"%s\"\n", url->host);
|
||||
return RTSP_ESYS;
|
||||
}
|
||||
not_ip:
|
||||
{
|
||||
g_warning ("host \"%s\" is not IP\n", url->host);
|
||||
return RTSP_ESYS;
|
||||
}
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_connection_create (gint fd, RTSPConnection ** conn)
|
||||
{
|
||||
RTSPConnection *newconn;
|
||||
|
||||
/* FIXME check fd */
|
||||
|
||||
newconn = g_new (RTSPConnection, 1);
|
||||
|
||||
newconn->fd = fd;
|
||||
newconn->cseq = 0;
|
||||
newconn->session_id[0] = 0;
|
||||
newconn->state = RTSP_STATE_INIT;
|
||||
|
||||
*conn = newconn;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
append_header (gint key, gchar * value, GString * str)
|
||||
{
|
||||
const gchar *keystr = rtsp_header_as_text (key);
|
||||
|
||||
g_string_append_printf (str, "%s: %s\r\n", keystr, value);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
||||
{
|
||||
GString *str;
|
||||
|
||||
if (conn == NULL || message == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
str = g_string_new ("");
|
||||
|
||||
g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
|
||||
"CSeq: %d\r\n",
|
||||
rtsp_method_as_text (message->type_data.request.method),
|
||||
message->type_data.request.uri, conn->cseq);
|
||||
|
||||
if (conn->session_id[0] != '\0') {
|
||||
rtsp_message_add_header (message, RTSP_HDR_SESSION, conn->session_id);
|
||||
}
|
||||
|
||||
g_hash_table_foreach (message->hdr_fields, (GHFunc) append_header, str);
|
||||
|
||||
|
||||
g_string_append (str, "\r\n");
|
||||
|
||||
write (conn->fd, str->str, str->len);
|
||||
g_string_free (str, TRUE);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static RTSPResult
|
||||
read_line (gint fd, gchar * buffer, guint size)
|
||||
{
|
||||
gint idx;
|
||||
gchar c;
|
||||
gint ret;
|
||||
|
||||
idx = 0;
|
||||
while (TRUE) {
|
||||
ret = read (fd, &c, 1);
|
||||
if (ret < 1)
|
||||
goto error;
|
||||
|
||||
if (c == '\n') /* end on \n */
|
||||
break;
|
||||
if (c == '\r') /* ignore \r */
|
||||
continue;
|
||||
|
||||
if (idx < size - 1)
|
||||
buffer[idx++] = c;
|
||||
}
|
||||
buffer[idx] = '\0';
|
||||
|
||||
return RTSP_OK;
|
||||
|
||||
error:
|
||||
{
|
||||
perror ("read");
|
||||
return 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 RTSPResult
|
||||
parse_response_status (gchar * buffer, RTSPMessage * msg)
|
||||
{
|
||||
gchar versionstr[20];
|
||||
gchar codestr[4];
|
||||
gint code;
|
||||
gchar *bptr;
|
||||
|
||||
bptr = buffer;
|
||||
|
||||
read_string (versionstr, sizeof (versionstr), &bptr);
|
||||
if (strcmp (versionstr, "RTSP/1.0") != 0)
|
||||
goto wrong_version;
|
||||
|
||||
read_string (codestr, sizeof (codestr), &bptr);
|
||||
code = atoi (codestr);
|
||||
|
||||
while (g_ascii_isspace (*bptr))
|
||||
bptr++;
|
||||
|
||||
rtsp_message_init_response (code, bptr, NULL, msg);
|
||||
|
||||
return RTSP_OK;
|
||||
|
||||
wrong_version:
|
||||
{
|
||||
return RTSP_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
static RTSPResult
|
||||
parse_line (gchar * buffer, RTSPMessage * msg)
|
||||
{
|
||||
gchar key[32];
|
||||
gchar *bptr;
|
||||
RTSPHeaderField field;
|
||||
|
||||
bptr = buffer;
|
||||
|
||||
read_key (key, sizeof (key), &bptr);
|
||||
if (*bptr != ':')
|
||||
return RTSP_EINVAL;
|
||||
|
||||
bptr++;
|
||||
|
||||
field = rtsp_find_header_field (key);
|
||||
if (field == -1) {
|
||||
g_warning ("unknown header field '%s'\n", key);
|
||||
} else {
|
||||
while (g_ascii_isspace (*bptr))
|
||||
bptr++;
|
||||
rtsp_message_add_header (msg, field, bptr);
|
||||
}
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static RTSPResult
|
||||
read_body (gint fd, glong content_length, RTSPMessage * msg)
|
||||
{
|
||||
gchar *body, *bodyptr;
|
||||
gint to_read, r;
|
||||
|
||||
if (content_length <= 0) {
|
||||
rtsp_message_set_body (msg, NULL, 0);
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
body = g_malloc (content_length);
|
||||
bodyptr = body;
|
||||
to_read = content_length;
|
||||
while (to_read > 0) {
|
||||
r = read (fd, bodyptr, to_read);
|
||||
|
||||
to_read -= r;
|
||||
bodyptr += r;
|
||||
}
|
||||
|
||||
rtsp_message_set_body (msg, body, content_length);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_connection_receive (RTSPConnection * conn, RTSPMessage * msg)
|
||||
{
|
||||
gchar buffer[4096];
|
||||
gint line;
|
||||
gchar *hdrval;
|
||||
glong content_length;
|
||||
RTSPResult res;
|
||||
gboolean need_body;
|
||||
|
||||
if (conn == NULL || msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
line = 0;
|
||||
|
||||
need_body = TRUE;
|
||||
|
||||
/* parse first line and headers */
|
||||
while (TRUE) {
|
||||
gchar c;
|
||||
gint ret;
|
||||
|
||||
ret = read (conn->fd, &c, 1);
|
||||
if (ret < 0)
|
||||
goto read_error;
|
||||
if (ret < 1)
|
||||
break;
|
||||
|
||||
/* check for data packet */
|
||||
if (c == '$') {
|
||||
guint16 size;
|
||||
|
||||
/* read channel */
|
||||
ret = read (conn->fd, &c, 1);
|
||||
if (ret < 0)
|
||||
goto read_error;
|
||||
if (ret < 1)
|
||||
goto error;
|
||||
|
||||
rtsp_message_init_data ((gint) c, msg);
|
||||
|
||||
ret = read (conn->fd, &size, 2);
|
||||
if (ret < 0)
|
||||
goto read_error;
|
||||
if (ret < 2)
|
||||
goto error;
|
||||
|
||||
size = GUINT16_FROM_BE (size);
|
||||
|
||||
read_body (conn->fd, size, msg);
|
||||
need_body = FALSE;
|
||||
break;
|
||||
} else {
|
||||
gint offset = 0;
|
||||
|
||||
if (c != '\r') {
|
||||
buffer[0] = c;
|
||||
offset = 1;
|
||||
}
|
||||
/* should not happen */
|
||||
if (c == '\n')
|
||||
break;
|
||||
|
||||
read_line (conn->fd, buffer + offset, sizeof (buffer) - offset);
|
||||
|
||||
if (buffer[0] == '\0')
|
||||
break;
|
||||
|
||||
if (line == 0) {
|
||||
if (g_str_has_prefix (buffer, "RTSP")) {
|
||||
parse_response_status (buffer, msg);
|
||||
} else {
|
||||
g_warning ("parsing request not implemented\n");
|
||||
goto error;
|
||||
}
|
||||
} else {
|
||||
parse_line (buffer, msg);
|
||||
}
|
||||
}
|
||||
line++;
|
||||
}
|
||||
|
||||
if (need_body) {
|
||||
/* parse body */
|
||||
res = rtsp_message_get_header (msg, RTSP_HDR_CONTENT_LENGTH, &hdrval);
|
||||
if (res == RTSP_OK) {
|
||||
content_length = atol (hdrval);
|
||||
read_body (conn->fd, content_length, msg);
|
||||
}
|
||||
|
||||
/* save session id */
|
||||
{
|
||||
gchar *session_id;
|
||||
|
||||
if (rtsp_message_get_header (msg, RTSP_HDR_SESSION,
|
||||
&session_id) == RTSP_OK) {
|
||||
strncpy (conn->session_id, session_id, sizeof (conn->session_id) - 1);
|
||||
conn->session_id[sizeof (conn->session_id) - 1] = '\0';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return RTSP_OK;
|
||||
|
||||
error:
|
||||
{
|
||||
return RTSP_EPARSE;
|
||||
}
|
||||
read_error:
|
||||
{
|
||||
perror ("read");
|
||||
return RTSP_ESYS;
|
||||
}
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_connection_close (RTSPConnection * conn)
|
||||
{
|
||||
gint res;
|
||||
|
||||
if (conn == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
res = close (conn->fd);
|
||||
conn->fd = -1;
|
||||
if (res != 0)
|
||||
goto sys_error;
|
||||
|
||||
return RTSP_OK;
|
||||
|
||||
sys_error:
|
||||
{
|
||||
return RTSP_ESYS;
|
||||
}
|
||||
}
|
56
gst/rtsp/rtspconnection.h
Normal file
56
gst/rtsp/rtspconnection.h
Normal file
|
@ -0,0 +1,56 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_CONNECTION_H__
|
||||
#define __RTSP_CONNECTION_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <rtspdefs.h>
|
||||
#include <rtspurl.h>
|
||||
#include <rtspstream.h>
|
||||
#include <rtspmessage.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _RTSPConnection
|
||||
{
|
||||
gint fd;
|
||||
|
||||
gint cseq;
|
||||
gchar session_id[512];
|
||||
|
||||
RTSPState state;
|
||||
|
||||
int num_streams;
|
||||
RTSPStream **streams;
|
||||
|
||||
} RTSPConnection;
|
||||
|
||||
RTSPResult rtsp_connection_open (RTSPUrl *url, RTSPConnection **conn);
|
||||
RTSPResult rtsp_connection_create (gint fd, RTSPConnection **conn);
|
||||
|
||||
RTSPResult rtsp_connection_send (RTSPConnection *conn, RTSPMessage *message);
|
||||
RTSPResult rtsp_connection_receive (RTSPConnection *conn, RTSPMessage *message);
|
||||
|
||||
RTSPResult rtsp_connection_close (RTSPConnection *conn);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_CONNECTION_H__ */
|
171
gst/rtsp/rtspdefs.c
Normal file
171
gst/rtsp/rtspdefs.c
Normal file
|
@ -0,0 +1,171 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include "rtspdefs.h"
|
||||
|
||||
const gchar *rtsp_methods[] = {
|
||||
"DESCRIBE",
|
||||
"ANNOUNCE",
|
||||
"GET_PARAMETER",
|
||||
"OPTIONS",
|
||||
"PAUSE",
|
||||
"PLAY",
|
||||
"RECORD",
|
||||
"REDIRECT",
|
||||
"SETUP",
|
||||
"SET_PARAMETER",
|
||||
"TEARDOWN",
|
||||
NULL
|
||||
};
|
||||
|
||||
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 */
|
||||
NULL
|
||||
};
|
||||
|
||||
#define DEF_STATUS(c,t)
|
||||
|
||||
void
|
||||
rtsp_init_status (void)
|
||||
{
|
||||
DEF_STATUS (RTSP_STS_CONTINUE, "Continue");
|
||||
DEF_STATUS (RTSP_STS_OK, "OK");
|
||||
DEF_STATUS (RTSP_STS_CREATED, "Created");
|
||||
DEF_STATUS (RTSP_STS_LOW_ON_STORAGE, "Low on Storage Space");
|
||||
DEF_STATUS (RTSP_STS_MULTIPLE_CHOICES, "Multiple Choices");
|
||||
DEF_STATUS (RTSP_STS_MOVED_PERMANENTLY, "Moved Permanently");
|
||||
DEF_STATUS (RTSP_STS_MOVE_TEMPORARILY, "Moved Temporarily");
|
||||
DEF_STATUS (RTSP_STS_SEE_OTHER, "See Other");
|
||||
DEF_STATUS (RTSP_STS_NOT_MODIFIED, "Not Modified");
|
||||
DEF_STATUS (RTSP_STS_USE_PROXY, "Use Proxy");
|
||||
DEF_STATUS (RTSP_STS_BAD_REQUEST, "Bad Request");
|
||||
DEF_STATUS (RTSP_STS_UNAUTHORIZED, "Unauthorized");
|
||||
DEF_STATUS (RTSP_STS_PAYMENT_REQUIRED, "Payment Required");
|
||||
DEF_STATUS (RTSP_STS_FORBIDDEN, "Forbidden");
|
||||
DEF_STATUS (RTSP_STS_NOT_FOUND, "Not Found");
|
||||
DEF_STATUS (RTSP_STS_METHOD_NOT_ALLOWED, "Method Not Allowed");
|
||||
DEF_STATUS (RTSP_STS_NOT_ACCEPTABLE, "Not Acceptable");
|
||||
DEF_STATUS (RTSP_STS_PROXY_AUTH_REQUIRED, "Proxy Authentication Required");
|
||||
DEF_STATUS (RTSP_STS_REQUEST_TIMEOUT, "Request Time-out");
|
||||
DEF_STATUS (RTSP_STS_GONE, "Gone");
|
||||
DEF_STATUS (RTSP_STS_LENGTH_REQUIRED, "Length Required");
|
||||
DEF_STATUS (RTSP_STS_PRECONDITION_FAILED, "Precondition Failed");
|
||||
DEF_STATUS (RTSP_STS_REQUEST_ENTITY_TOO_LARGE, "Request Entity Too Large");
|
||||
DEF_STATUS (RTSP_STS_REQUEST_URI_TOO_LARGE, "Request-URI Too Large");
|
||||
DEF_STATUS (RTSP_STS_UNSUPPORTED_MEDIA_TYPE, "Unsupported Media Type");
|
||||
DEF_STATUS (RTSP_STS_PARAMETER_NOT_UNDERSTOOD, "Parameter Not Understood");
|
||||
DEF_STATUS (RTSP_STS_CONFERENCE_NOT_FOUND, "Conference Not Found");
|
||||
DEF_STATUS (RTSP_STS_NOT_ENOUGH_BANDWIDTH, "Not Enough Bandwidth");
|
||||
DEF_STATUS (RTSP_STS_SESSION_NOT_FOUND, "Session Not Found");
|
||||
DEF_STATUS (RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE,
|
||||
"Method Not Valid in This State");
|
||||
DEF_STATUS (RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE,
|
||||
"Header Field Not Valid for Resource");
|
||||
DEF_STATUS (RTSP_STS_INVALID_RANGE, "Invalid Range");
|
||||
DEF_STATUS (RTSP_STS_PARAMETER_IS_READONLY, "Parameter Is Read-Only");
|
||||
DEF_STATUS (RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED,
|
||||
"Aggregate operation not allowed");
|
||||
DEF_STATUS (RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED,
|
||||
"Only aggregate operation allowed");
|
||||
DEF_STATUS (RTSP_STS_UNSUPPORTED_TRANSPORT, "Unsupported transport");
|
||||
DEF_STATUS (RTSP_STS_DESTINATION_UNREACHABLE, "Destination unreachable");
|
||||
DEF_STATUS (RTSP_STS_INTERNAL_SERVER_ERROR, "Internal Server Error");
|
||||
DEF_STATUS (RTSP_STS_NOT_IMPLEMENTED, "Not Implemented");
|
||||
DEF_STATUS (RTSP_STS_BAD_GATEWAY, "Bad Gateway");
|
||||
DEF_STATUS (RTSP_STS_SERVICE_UNAVAILABLE, "Service Unavailable");
|
||||
DEF_STATUS (RTSP_STS_GATEWAY_TIMEOUT, "Gateway Time-out");
|
||||
DEF_STATUS (RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
|
||||
"RTSP Version not supported");
|
||||
DEF_STATUS (RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
|
||||
}
|
||||
|
||||
const gchar *
|
||||
rtsp_method_as_text (RTSPMethod method)
|
||||
{
|
||||
return rtsp_methods[method];
|
||||
}
|
||||
|
||||
const gchar *
|
||||
rtsp_header_as_text (RTSPHeaderField field)
|
||||
{
|
||||
return rtsp_headers[field];
|
||||
}
|
||||
|
||||
const gchar *
|
||||
rtsp_status_as_text (RTSPStatusCode code)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const gchar *
|
||||
rtsp_status_to_string (RTSPStatusCode code)
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RTSPHeaderField
|
||||
rtsp_find_header_field (gchar * header)
|
||||
{
|
||||
gint idx;
|
||||
|
||||
for (idx = 0; rtsp_headers[idx]; idx++) {
|
||||
if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) {
|
||||
return idx;
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
174
gst/rtsp/rtspdefs.h
Normal file
174
gst/rtsp/rtspdefs.h
Normal file
|
@ -0,0 +1,174 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_DEFS_H__
|
||||
#define __RTSP_DEFS_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
RTSP_OK = 0,
|
||||
/* errors */
|
||||
RTSP_EINVAL = -1,
|
||||
RTSP_ENOMEM = -2,
|
||||
RTSP_ERESOLV = -3,
|
||||
RTSP_ENOTIMPL = -4,
|
||||
RTSP_ESYS = -5,
|
||||
RTSP_EPARSE = -6,
|
||||
} RTSPResult;
|
||||
|
||||
typedef enum {
|
||||
RTSP_PROTO_TCP,
|
||||
RTSP_PROTO_UDP,
|
||||
} RTSPProto;
|
||||
|
||||
typedef enum {
|
||||
RTSP_FAM_NONE,
|
||||
RTSP_FAM_INET,
|
||||
RTSP_FAM_INET6,
|
||||
} RTSPFamily;
|
||||
|
||||
typedef enum {
|
||||
RTSP_STATE_INIT,
|
||||
RTSP_STATE_READY,
|
||||
RTSP_STATE_PLAYING,
|
||||
RTSP_STATE_RECORDING,
|
||||
} RTSPState;
|
||||
|
||||
typedef enum {
|
||||
RTSP_DESCRIBE,
|
||||
RTSP_ANNOUNCE,
|
||||
RTSP_GET_PARAMETER,
|
||||
RTSP_OPTIONS,
|
||||
RTSP_PAUSE,
|
||||
RTSP_PLAY,
|
||||
RTSP_RECORD,
|
||||
RTSP_REDIRECT,
|
||||
RTSP_SETUP,
|
||||
RTSP_SET_PARAMETER,
|
||||
RTSP_TEARDOWN,
|
||||
} RTSPMethod;
|
||||
|
||||
typedef enum {
|
||||
/*
|
||||
* R = Request
|
||||
* r = response
|
||||
* g = general
|
||||
* e = entity
|
||||
*/
|
||||
RTSP_HDR_ACCEPT, /* Accept R opt. entity */
|
||||
RTSP_HDR_ACCEPT_ENCODING, /* Accept-Encoding R opt. entity */
|
||||
RTSP_HDR_ACCEPT_LANGUAGE, /* Accept-Language R opt. all */
|
||||
RTSP_HDR_ALLOW, /* Allow r opt. all */
|
||||
RTSP_HDR_AUTHORIZATION, /* Authorization R opt. all */
|
||||
RTSP_HDR_BANDWIDTH, /* Bandwidth R opt. all */
|
||||
RTSP_HDR_BLOCKSIZE, /* Blocksize R opt. all but OPTIONS, TEARDOWN */
|
||||
RTSP_HDR_CACHE_CONTROL, /* Cache-Control g opt. SETUP */
|
||||
RTSP_HDR_CONFERENCE, /* Conference R opt. SETUP */
|
||||
RTSP_HDR_CONNECTION, /* Connection g req. all */
|
||||
RTSP_HDR_CONTENT_BASE, /* Content-Base e opt. entity */
|
||||
RTSP_HDR_CONTENT_ENCODING, /* Content-Encoding e req. SET_PARAMETER, DESCRIBE, ANNOUNCE */
|
||||
RTSP_HDR_CONTENT_LANGUAGE, /* Content-Language e req. DESCRIBE, ANNOUNCE */
|
||||
RTSP_HDR_CONTENT_LENGTH, /* Content-Length e req. SET_PARAMETER, ANNOUNCE, entity */
|
||||
RTSP_HDR_CONTENT_LOCATION, /* Content-Location e opt. entity */
|
||||
RTSP_HDR_CONTENT_TYPE, /* Content-Type e req. SET_PARAMETER, ANNOUNCE, entity */
|
||||
RTSP_HDR_CSEQ, /* CSeq g req. all */
|
||||
RTSP_HDR_DATE, /* Date g opt. all */
|
||||
RTSP_HDR_EXPIRES, /* Expires e opt. DESCRIBE, ANNOUNCE */
|
||||
RTSP_HDR_FROM, /* From R opt. all */
|
||||
RTSP_HDR_IF_MODIFIED_SINCE, /* If-Modified-Since R opt. DESCRIBE, SETUP */
|
||||
RTSP_HDR_LAST_MODIFIED, /* Last-Modified e opt. entity */
|
||||
RTSP_HDR_PROXY_AUTHENTICATE, /* Proxy-Authenticate */
|
||||
RTSP_HDR_PROXY_REQUIRE, /* Proxy-Require R req. all */
|
||||
RTSP_HDR_PUBLIC, /* Public r opt. all */
|
||||
RTSP_HDR_RANGE, /* Range Rr opt. PLAY, PAUSE, RECORD */
|
||||
RTSP_HDR_REFERER, /* Referer R opt. all */
|
||||
RTSP_HDR_REQUIRE, /* Require R req. all */
|
||||
RTSP_HDR_RETRY_AFTER, /* Retry-After r opt. all */
|
||||
RTSP_HDR_RTP_INFO, /* RTP-Info r req. PLAY */
|
||||
RTSP_HDR_SCALE, /* Scale Rr opt. PLAY, RECORD */
|
||||
RTSP_HDR_SESSION, /* Session Rr req. all but SETUP, OPTIONS */
|
||||
RTSP_HDR_SERVER, /* Server r opt. all */
|
||||
RTSP_HDR_SPEED, /* Speed Rr opt. PLAY */
|
||||
RTSP_HDR_TRANSPORT, /* Transport Rr req. SETUP */
|
||||
RTSP_HDR_UNSUPPORTED, /* Unsupported r req. all */
|
||||
RTSP_HDR_USER_AGENT, /* User-Agent R opt. all */
|
||||
RTSP_HDR_VIA, /* Via g opt. all */
|
||||
RTSP_HDR_WWW_AUTHENTICATE, /* WWW-Authenticate r opt. all */
|
||||
|
||||
} RTSPHeaderField;
|
||||
|
||||
typedef enum {
|
||||
RTSP_STS_CONTINUE = 100,
|
||||
RTSP_STS_OK = 200,
|
||||
RTSP_STS_CREATED = 201,
|
||||
RTSP_STS_LOW_ON_STORAGE = 250,
|
||||
RTSP_STS_MULTIPLE_CHOICES = 300,
|
||||
RTSP_STS_MOVED_PERMANENTLY = 301,
|
||||
RTSP_STS_MOVE_TEMPORARILY = 302,
|
||||
RTSP_STS_SEE_OTHER = 303,
|
||||
RTSP_STS_NOT_MODIFIED = 304,
|
||||
RTSP_STS_USE_PROXY = 305,
|
||||
RTSP_STS_BAD_REQUEST = 400,
|
||||
RTSP_STS_UNAUTHORIZED = 401,
|
||||
RTSP_STS_PAYMENT_REQUIRED = 402,
|
||||
RTSP_STS_FORBIDDEN = 403,
|
||||
RTSP_STS_NOT_FOUND = 404,
|
||||
RTSP_STS_METHOD_NOT_ALLOWED = 405,
|
||||
RTSP_STS_NOT_ACCEPTABLE = 406,
|
||||
RTSP_STS_PROXY_AUTH_REQUIRED = 407,
|
||||
RTSP_STS_REQUEST_TIMEOUT = 408,
|
||||
RTSP_STS_GONE = 410,
|
||||
RTSP_STS_LENGTH_REQUIRED = 411,
|
||||
RTSP_STS_PRECONDITION_FAILED = 412,
|
||||
RTSP_STS_REQUEST_ENTITY_TOO_LARGE = 413,
|
||||
RTSP_STS_REQUEST_URI_TOO_LARGE = 414,
|
||||
RTSP_STS_UNSUPPORTED_MEDIA_TYPE = 415,
|
||||
RTSP_STS_PARAMETER_NOT_UNDERSTOOD = 451,
|
||||
RTSP_STS_CONFERENCE_NOT_FOUND = 452,
|
||||
RTSP_STS_NOT_ENOUGH_BANDWIDTH = 453,
|
||||
RTSP_STS_SESSION_NOT_FOUND = 454,
|
||||
RTSP_STS_METHOD_NOT_VALID_IN_THIS_STATE = 455,
|
||||
RTSP_STS_HEADER_FIELD_NOT_VALID_FOR_RESOURCE = 456,
|
||||
RTSP_STS_INVALID_RANGE = 457,
|
||||
RTSP_STS_PARAMETER_IS_READONLY = 458,
|
||||
RTSP_STS_AGGREGATE_OPERATION_NOT_ALLOWED = 459,
|
||||
RTSP_STS_ONLY_AGGREGATE_OPERATION_ALLOWED = 460,
|
||||
RTSP_STS_UNSUPPORTED_TRANSPORT = 461,
|
||||
RTSP_STS_DESTINATION_UNREACHABLE = 462,
|
||||
RTSP_STS_INTERNAL_SERVER_ERROR = 500,
|
||||
RTSP_STS_NOT_IMPLEMENTED = 501,
|
||||
RTSP_STS_BAD_GATEWAY = 502,
|
||||
RTSP_STS_SERVICE_UNAVAILABLE = 503,
|
||||
RTSP_STS_GATEWAY_TIMEOUT = 504,
|
||||
RTSP_STS_RTSP_VERSION_NOT_SUPPORTED = 505,
|
||||
RTSP_STS_OPTION_NOT_SUPPORTED = 551,
|
||||
} RTSPStatusCode;
|
||||
|
||||
const gchar* rtsp_method_as_text (RTSPMethod method);
|
||||
const gchar* rtsp_header_as_text (RTSPHeaderField field);
|
||||
const gchar* rtsp_status_as_text (RTSPStatusCode code);
|
||||
const gchar* rtsp_status_to_string (RTSPStatusCode code);
|
||||
RTSPHeaderField rtsp_find_header_field (gchar *header);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_DEFS_H__ */
|
307
gst/rtsp/rtspmessage.c
Normal file
307
gst/rtsp/rtspmessage.c
Normal file
|
@ -0,0 +1,307 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include "rtspmessage.h"
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_new_request (RTSPMethod method, gchar * uri, RTSPMessage ** msg)
|
||||
{
|
||||
RTSPMessage *newmsg;
|
||||
|
||||
if (msg == NULL || uri == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
newmsg = g_new0 (RTSPMessage, 1);
|
||||
|
||||
*msg = newmsg;
|
||||
|
||||
return rtsp_message_init_request (method, uri, newmsg);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_init_request (RTSPMethod method, gchar * uri, RTSPMessage * msg)
|
||||
{
|
||||
if (msg == NULL || uri == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
msg->type = RTSP_MESSAGE_REQUEST;
|
||||
msg->type_data.request.method = method;
|
||||
g_free (msg->type_data.request.uri);
|
||||
msg->type_data.request.uri = g_strdup (uri);
|
||||
|
||||
if (msg->hdr_fields != NULL)
|
||||
g_hash_table_destroy (msg->hdr_fields);
|
||||
msg->hdr_fields =
|
||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
||||
|
||||
if (msg->body) {
|
||||
g_free (msg->body);
|
||||
msg->body = NULL;
|
||||
}
|
||||
msg->body_size = 0;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_new_response (RTSPStatusCode code, gchar * reason,
|
||||
RTSPMessage * request, RTSPMessage ** msg)
|
||||
{
|
||||
RTSPMessage *newmsg;
|
||||
|
||||
if (msg == NULL || reason == NULL || request == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
newmsg = g_new0 (RTSPMessage, 1);
|
||||
|
||||
*msg = newmsg;
|
||||
|
||||
return rtsp_message_init_response (code, reason, request, newmsg);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_init_response (RTSPStatusCode code, gchar * reason,
|
||||
RTSPMessage * request, RTSPMessage * msg)
|
||||
{
|
||||
if (reason == NULL || msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
msg->type = RTSP_MESSAGE_RESPONSE;
|
||||
msg->type_data.response.code = code;
|
||||
g_free (msg->type_data.response.reason);
|
||||
msg->type_data.response.reason = g_strdup (reason);
|
||||
|
||||
if (msg->hdr_fields != NULL)
|
||||
g_hash_table_destroy (msg->hdr_fields);
|
||||
msg->hdr_fields =
|
||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
||||
|
||||
if (msg->body) {
|
||||
g_free (msg->body);
|
||||
msg->body = NULL;
|
||||
}
|
||||
msg->body_size = 0;
|
||||
|
||||
if (request) {
|
||||
/* FIXME copy headers */
|
||||
}
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_init_data (gint channel, RTSPMessage * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
msg->type = RTSP_MESSAGE_DATA;
|
||||
msg->type_data.data.channel = channel;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
|
||||
gchar * value)
|
||||
{
|
||||
if (msg == NULL || value == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
g_hash_table_insert (msg->hdr_fields, GINT_TO_POINTER (field),
|
||||
g_strdup (value));
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
g_hash_table_remove (msg->hdr_fields, GINT_TO_POINTER (field));
|
||||
|
||||
return RTSP_ENOTIMPL;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_get_header (RTSPMessage * msg, RTSPHeaderField field,
|
||||
gchar ** value)
|
||||
{
|
||||
gchar *val;
|
||||
|
||||
if (msg == NULL || value == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
|
||||
if (val == NULL)
|
||||
return RTSP_ENOTIMPL;
|
||||
|
||||
*value = val;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_get_header_copy (RTSPMessage * msg, RTSPHeaderField field,
|
||||
gchar ** value)
|
||||
{
|
||||
gchar *val;
|
||||
|
||||
if (msg == NULL || value == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
|
||||
|
||||
*value = g_strdup (val);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
if (msg->body)
|
||||
g_free (msg->body);
|
||||
|
||||
msg->body = data;
|
||||
msg->body_size = size;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_set_body_copy (RTSPMessage * msg, guint8 * data, guint size)
|
||||
{
|
||||
return RTSP_ENOTIMPL;
|
||||
}
|
||||
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
|
||||
{
|
||||
if (msg == NULL || data == NULL || size == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
*data = msg->body;
|
||||
*size = msg->body_size;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_get_body_copy (RTSPMessage * msg, guint8 ** data, guint * size)
|
||||
{
|
||||
if (msg == NULL || data == NULL || size == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
*data = g_memdup (msg->body, msg->body_size);
|
||||
*size = msg->body_size;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
dump_mem (guint8 * mem, gint 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 key, gpointer value, gpointer data)
|
||||
{
|
||||
RTSPHeaderField field = GPOINTER_TO_INT (key);
|
||||
|
||||
g_print (" key: '%s', value: '%s'\n", rtsp_header_as_text (field),
|
||||
(gchar *) value);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_message_dump (RTSPMessage * msg)
|
||||
{
|
||||
guint8 *data;
|
||||
guint size;
|
||||
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
if (msg->type == RTSP_MESSAGE_REQUEST) {
|
||||
g_print ("request message %p\n", msg);
|
||||
g_print (" request line:\n");
|
||||
g_print (" method: '%s'\n",
|
||||
rtsp_method_as_text (msg->type_data.request.method));
|
||||
g_print (" uri: '%s'\n", msg->type_data.request.uri);
|
||||
g_print (" headers:\n");
|
||||
g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
|
||||
g_print (" body:\n");
|
||||
rtsp_message_get_body (msg, &data, &size);
|
||||
dump_mem (data, size);
|
||||
} else if (msg->type == RTSP_MESSAGE_RESPONSE) {
|
||||
g_print ("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 (" headers:\n");
|
||||
g_hash_table_foreach (msg->hdr_fields, dump_key_value, NULL);
|
||||
g_print (" body:\n");
|
||||
rtsp_message_get_body (msg, &data, &size);
|
||||
dump_mem (data, size);
|
||||
} else if (msg->type == RTSP_MESSAGE_DATA) {
|
||||
g_print ("data message %p\n", msg);
|
||||
g_print (" channel: '%d'\n", msg->type_data.data.channel);
|
||||
g_print (" size: '%d'\n", msg->body_size);
|
||||
rtsp_message_get_body (msg, &data, &size);
|
||||
dump_mem (data, size);
|
||||
} else {
|
||||
g_print ("unsupported packet type %d\n", msg->type);
|
||||
return RTSP_EINVAL;
|
||||
}
|
||||
return RTSP_OK;
|
||||
}
|
88
gst/rtsp/rtspmessage.h
Normal file
88
gst/rtsp/rtspmessage.h
Normal file
|
@ -0,0 +1,88 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_MESSAGE_H__
|
||||
#define __RTSP_MESSAGE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <rtspdefs.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum
|
||||
{
|
||||
RTSP_MESSAGE_REQUEST,
|
||||
RTSP_MESSAGE_RESPONSE,
|
||||
RTSP_MESSAGE_DATA,
|
||||
} RTSPMsgType;
|
||||
|
||||
typedef struct _RTSPMessage
|
||||
{
|
||||
RTSPMsgType type;
|
||||
|
||||
union {
|
||||
struct {
|
||||
RTSPMethod method;
|
||||
gchar *uri;
|
||||
} request;
|
||||
struct {
|
||||
RTSPStatusCode code;
|
||||
gchar *reason;
|
||||
} response;
|
||||
struct {
|
||||
gint channel;
|
||||
} data;
|
||||
} type_data;
|
||||
|
||||
GHashTable *hdr_fields;
|
||||
|
||||
guint8 *body;
|
||||
guint body_size;
|
||||
|
||||
} RTSPMessage;
|
||||
|
||||
RTSPResult rtsp_message_new_request (RTSPMethod method, gchar *uri, RTSPMessage **msg);
|
||||
RTSPResult rtsp_message_init_request (RTSPMethod method, gchar *uri, RTSPMessage *msg);
|
||||
|
||||
RTSPResult rtsp_message_new_response (RTSPStatusCode code, gchar *reason,
|
||||
RTSPMessage *request, RTSPMessage **msg);
|
||||
RTSPResult rtsp_message_init_response (RTSPStatusCode code, gchar *reason,
|
||||
RTSPMessage *request, RTSPMessage *msg);
|
||||
RTSPResult rtsp_message_init_data (gint channel, RTSPMessage *msg);
|
||||
|
||||
RTSPResult rtsp_message_free (RTSPMessage *msg);
|
||||
|
||||
|
||||
RTSPResult rtsp_message_add_header (RTSPMessage *msg, RTSPHeaderField field, gchar *value);
|
||||
RTSPResult rtsp_message_remove_header (RTSPMessage *msg, RTSPHeaderField field);
|
||||
RTSPResult rtsp_message_get_header (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
|
||||
RTSPResult rtsp_message_get_header_copy (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
|
||||
|
||||
RTSPResult rtsp_message_set_body (RTSPMessage *msg, guint8 *data, guint size);
|
||||
RTSPResult rtsp_message_set_body_copy (RTSPMessage *msg, guint8 *data, guint size);
|
||||
|
||||
RTSPResult rtsp_message_get_body (RTSPMessage *msg, guint8 **data, guint *size);
|
||||
RTSPResult rtsp_message_get_body_copy (RTSPMessage *msg, guint8 **data, guint *size);
|
||||
|
||||
RTSPResult rtsp_message_dump (RTSPMessage *msg);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_MESSAGE_H__ */
|
32
gst/rtsp/rtspstream.h
Normal file
32
gst/rtsp/rtspstream.h
Normal file
|
@ -0,0 +1,32 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_STREAM_H__
|
||||
#define __RTSP_STREAM_H__
|
||||
|
||||
#include <rtspdefs.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct _RTSPStream {
|
||||
} RTSPStream;
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_STREAM_H__ */
|
144
gst/rtsp/rtsptransport.c
Normal file
144
gst/rtsp/rtsptransport.c
Normal file
|
@ -0,0 +1,144 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include "rtsptransport.h"
|
||||
|
||||
RTSPResult
|
||||
rtsp_transport_new (RTSPTransport ** transport)
|
||||
{
|
||||
RTSPTransport *trans;
|
||||
|
||||
if (transport == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
trans = g_new0 (RTSPTransport, 1);
|
||||
|
||||
*transport = trans;
|
||||
|
||||
return rtsp_transport_init (trans);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_transport_init (RTSPTransport * transport)
|
||||
{
|
||||
g_free (transport->destination);
|
||||
g_free (transport->source);
|
||||
g_free (transport->ssrc);
|
||||
|
||||
memset (transport, 0, sizeof (RTSPTransport));
|
||||
|
||||
transport->trans = RTSP_TRANS_RTP;
|
||||
transport->profile = RTSP_PROFILE_AVP;
|
||||
transport->lower_transport = RTSP_LOWER_TRANS_UNKNOWN;
|
||||
transport->mode_play = TRUE;
|
||||
transport->mode_record = FALSE;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_mode (RTSPTransport * transport, gchar * str)
|
||||
{
|
||||
if (strstr (str, "\"PLAY\""))
|
||||
transport->mode_play = TRUE;
|
||||
else
|
||||
transport->mode_play = FALSE;
|
||||
if (strstr (str, "\"RECORD\""))
|
||||
transport->mode_record = TRUE;
|
||||
else
|
||||
transport->mode_record = FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
parse_range (RTSPTransport * transport, gchar * str, RTSPRange * range)
|
||||
{
|
||||
gchar *minus;
|
||||
|
||||
minus = strstr (str, "-");
|
||||
if (minus) {
|
||||
range->min = atoi (str);
|
||||
range->max = atoi (minus + 1);
|
||||
} else {
|
||||
range->min = atoi (str);
|
||||
range->max = -1;
|
||||
}
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_transport_parse (gchar * str, RTSPTransport * transport)
|
||||
{
|
||||
gchar **split;
|
||||
gint i;
|
||||
|
||||
if (str == NULL || transport == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
rtsp_transport_init (transport);
|
||||
|
||||
split = g_strsplit (str, ";", 0);
|
||||
i = 0;
|
||||
while (split[i]) {
|
||||
if (g_str_has_prefix (split[i], "RTP/AVP/UDP")) {
|
||||
transport->lower_transport = RTSP_LOWER_TRANS_UDP;
|
||||
} else if (g_str_has_prefix (split[i], "RTP/AVP/TCP")) {
|
||||
transport->lower_transport = RTSP_LOWER_TRANS_TCP;
|
||||
} else if (g_str_has_prefix (split[i], "multicast")) {
|
||||
transport->multicast = TRUE;
|
||||
} else if (g_str_has_prefix (split[i], "unicast")) {
|
||||
transport->multicast = FALSE;
|
||||
} else if (g_str_has_prefix (split[i], "destination=")) {
|
||||
transport->destination = g_strdup (split[i] + 12);
|
||||
} else if (g_str_has_prefix (split[i], "source=")) {
|
||||
transport->source = g_strdup (split[i] + 7);
|
||||
} else if (g_str_has_prefix (split[i], "layers=")) {
|
||||
transport->layers = atoi (split[i] + 7);
|
||||
} else if (g_str_has_prefix (split[i], "mode=")) {
|
||||
parse_mode (transport, split[i] + 5);
|
||||
} else if (g_str_has_prefix (split[i], "append")) {
|
||||
transport->append = TRUE;
|
||||
} else if (g_str_has_prefix (split[i], "interleaved=")) {
|
||||
parse_range (transport, split[i] + 12, &transport->interleaved);
|
||||
} else if (g_str_has_prefix (split[i], "ttl=")) {
|
||||
transport->ttl = atoi (split[i] + 4);
|
||||
} else if (g_str_has_prefix (split[i], "port=")) {
|
||||
parse_range (transport, split[i] + 5, &transport->port);
|
||||
} else if (g_str_has_prefix (split[i], "client_port=")) {
|
||||
parse_range (transport, split[i] + 12, &transport->client_port);
|
||||
} else if (g_str_has_prefix (split[i], "server_port=")) {
|
||||
parse_range (transport, split[i] + 12, &transport->server_port);
|
||||
} else if (g_str_has_prefix (split[i], "ssrc=")) {
|
||||
transport->ssrc = g_strdup (split[i] + 5);
|
||||
} else {
|
||||
/* unknown field... */
|
||||
g_warning ("unknown transport field \"%s\"", split[i]);
|
||||
}
|
||||
i++;
|
||||
}
|
||||
g_strfreev (split);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
rtsp_transport_free (RTSPTransport * transport)
|
||||
{
|
||||
rtsp_transport_init (transport);
|
||||
g_free (transport);
|
||||
return RTSP_OK;
|
||||
}
|
81
gst/rtsp/rtsptransport.h
Normal file
81
gst/rtsp/rtsptransport.h
Normal file
|
@ -0,0 +1,81 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_TRANSPORT_H__
|
||||
#define __RTSP_TRANSPORT_H__
|
||||
|
||||
#include <rtspdefs.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef enum {
|
||||
RTSP_TRANS_RTP,
|
||||
} RTSPTransMode;
|
||||
|
||||
typedef enum {
|
||||
RTSP_PROFILE_AVP,
|
||||
} RTSPProfile;
|
||||
|
||||
typedef enum {
|
||||
RTSP_LOWER_TRANS_UNKNOWN,
|
||||
RTSP_LOWER_TRANS_UDP,
|
||||
RTSP_LOWER_TRANS_TCP,
|
||||
} RTSPLowerTrans;
|
||||
|
||||
typedef struct
|
||||
{
|
||||
gint min;
|
||||
gint max;
|
||||
} RTSPRange;
|
||||
|
||||
typedef struct _RTSPTransport {
|
||||
RTSPTransMode trans;
|
||||
RTSPProfile profile;
|
||||
RTSPLowerTrans lower_transport;
|
||||
|
||||
gboolean multicast;
|
||||
gchar *destination;
|
||||
gchar *source;
|
||||
gint layers;
|
||||
gboolean mode_play;
|
||||
gboolean mode_record;
|
||||
gboolean append;
|
||||
RTSPRange interleaved;
|
||||
|
||||
/* mulitcast specific */
|
||||
gint ttl;
|
||||
|
||||
/* RTP specific */
|
||||
RTSPRange port;
|
||||
RTSPRange client_port;
|
||||
RTSPRange server_port;
|
||||
gchar *ssrc;
|
||||
|
||||
} RTSPTransport;
|
||||
|
||||
RTSPResult rtsp_transport_new (RTSPTransport **transport);
|
||||
RTSPResult rtsp_transport_init (RTSPTransport *transport);
|
||||
|
||||
RTSPResult rtsp_transport_parse (gchar *str, RTSPTransport *transport);
|
||||
|
||||
RTSPResult rtsp_transport_free (RTSPTransport *transport);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_TRANSPORT_H__ */
|
101
gst/rtsp/rtspurl.c
Normal file
101
gst/rtsp/rtspurl.c
Normal file
|
@ -0,0 +1,101 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "rtspurl.h"
|
||||
|
||||
#define RTSP_PROTO "rtsp://"
|
||||
#define RTSP_PROTO_LEN 7
|
||||
#define RTSPU_PROTO "rtspu://"
|
||||
#define RTSPU_PROTO_LEN 8
|
||||
|
||||
/* format is rtsp[u]://[user:passwd@]host[:port]/abspath */
|
||||
|
||||
RTSPResult
|
||||
rtsp_url_parse (const gchar * urlstr, RTSPUrl ** url)
|
||||
{
|
||||
RTSPUrl *res;
|
||||
gchar *p, *slash, *at, *col;
|
||||
|
||||
res = g_new0 (RTSPUrl, 1);
|
||||
|
||||
p = (gchar *) urlstr;
|
||||
if (g_str_has_prefix (p, RTSP_PROTO)) {
|
||||
res->protocol = RTSP_PROTO_TCP;
|
||||
p += RTSP_PROTO_LEN;
|
||||
} else if (g_str_has_prefix (p, RTSPU_PROTO)) {
|
||||
res->protocol = RTSP_PROTO_UDP;
|
||||
p += RTSPU_PROTO_LEN;
|
||||
} else {
|
||||
return RTSP_EINVAL;
|
||||
}
|
||||
|
||||
slash = g_strrstr (p, "/");
|
||||
at = g_strrstr (p, "@");
|
||||
|
||||
if (at && slash && at > slash)
|
||||
at = NULL;
|
||||
|
||||
if (at) {
|
||||
col = g_strrstr (p, ":");
|
||||
|
||||
if (col == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
res->user = g_strndup (p, col - p);
|
||||
col++;
|
||||
res->passwd = g_strndup (col, col - at);
|
||||
|
||||
p = at + 1;
|
||||
}
|
||||
|
||||
col = g_strrstr (p, ":");
|
||||
if (col) {
|
||||
res->host = g_strndup (p, col - p);
|
||||
p = col + 1;
|
||||
res->port = strtoul (p, (char **) &p, 10);
|
||||
if (slash)
|
||||
p = slash + 1;
|
||||
} else {
|
||||
res->port = RTSP_DEFAULT_PORT;
|
||||
if (!slash) {
|
||||
res->host = g_strdup (p);
|
||||
p = NULL;
|
||||
} else {
|
||||
res->host = g_strndup (p, slash - p);
|
||||
p = slash + 1;
|
||||
}
|
||||
}
|
||||
if (p)
|
||||
res->abspath = g_strdup (p);
|
||||
|
||||
*url = res;
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
void
|
||||
rtsp_url_free (RTSPUrl * url)
|
||||
{
|
||||
g_free (url->user);
|
||||
g_free (url->passwd);
|
||||
g_free (url->host);
|
||||
g_free (url->abspath);
|
||||
g_free (url);
|
||||
}
|
46
gst/rtsp/rtspurl.h
Normal file
46
gst/rtsp/rtspurl.h
Normal file
|
@ -0,0 +1,46 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __RTSP_URL_H__
|
||||
#define __RTSP_URL_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <rtspdefs.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
#define RTSP_DEFAULT_PORT 554
|
||||
|
||||
typedef struct _RTSPUrl {
|
||||
RTSPProto protocol;
|
||||
RTSPFamily family;
|
||||
gchar *user;
|
||||
gchar *passwd;
|
||||
gchar *host;
|
||||
guint16 port;
|
||||
gchar *abspath;
|
||||
} RTSPUrl;
|
||||
|
||||
RTSPResult rtsp_url_parse (const gchar *urlstr, RTSPUrl **url);
|
||||
void rtsp_url_free (RTSPUrl *url);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __RTSP_URL_H__ */
|
25
gst/rtsp/sdp.h
Normal file
25
gst/rtsp/sdp.h
Normal file
|
@ -0,0 +1,25 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __SDP_H__
|
||||
#define __SDP_H__
|
||||
|
||||
#include <sdpmessage.h>
|
||||
|
||||
#endif /* __SDP_H__ */
|
709
gst/rtsp/sdpmessage.c
Normal file
709
gst/rtsp/sdpmessage.c
Normal file
|
@ -0,0 +1,709 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "sdpmessage.h"
|
||||
|
||||
#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) \
|
||||
G_STMT_START { \
|
||||
if (field) \
|
||||
g_array_set_size (field,0); \
|
||||
else \
|
||||
field = g_array_new (FALSE, TRUE, sizeof(type)); \
|
||||
} G_STMT_END
|
||||
|
||||
#define DEFINE_STRING_SETTER(field) \
|
||||
RTSPResult sdp_message_set_##field (SDPMessage *msg, gchar *val) { \
|
||||
g_free (msg->field); \
|
||||
msg->field = g_strdup (val); \
|
||||
return RTSP_OK; \
|
||||
}
|
||||
#define DEFINE_STRING_GETTER(field) \
|
||||
char* sdp_message_get_##field (SDPMessage *msg) { \
|
||||
return msg->field; \
|
||||
}
|
||||
|
||||
#define DEFINE_ARRAY_LEN(field) \
|
||||
gint sdp_message_##field##_len (SDPMessage *msg) { \
|
||||
return ((msg)->field->len); \
|
||||
}
|
||||
#define DEFINE_ARRAY_GETTER(method,field,type) \
|
||||
type sdp_message_get_##method (SDPMessage *msg, gint i) { \
|
||||
return g_array_index ((msg)->field, type, i); \
|
||||
}
|
||||
#define DEFINE_ARRAY_P_GETTER(method,field,type) \
|
||||
type * sdp_message_get_##method (SDPMessage *msg, gint i) { \
|
||||
return &g_array_index ((msg)->field, type, i); \
|
||||
}
|
||||
#define DEFINE_ARRAY_ADDER(method,field,type,dup_method) \
|
||||
RTSPResult sdp_message_add_##method (SDPMessage *msg, type val) { \
|
||||
type v = dup_method(val); \
|
||||
g_array_append_val((msg)->field, v); \
|
||||
return RTSP_OK; \
|
||||
}
|
||||
|
||||
|
||||
|
||||
RTSPResult
|
||||
sdp_message_new (SDPMessage ** msg)
|
||||
{
|
||||
SDPMessage *newmsg;
|
||||
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
newmsg = g_new0 (SDPMessage, 1);
|
||||
|
||||
*msg = newmsg;
|
||||
|
||||
return sdp_message_init (newmsg);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_init (SDPMessage * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
FREE_STRING (msg->version);
|
||||
FREE_STRING (msg->origin.username);
|
||||
FREE_STRING (msg->origin.sess_id);
|
||||
FREE_STRING (msg->origin.sess_version);
|
||||
FREE_STRING (msg->origin.nettype);
|
||||
FREE_STRING (msg->origin.addrtype);
|
||||
FREE_STRING (msg->origin.addr);
|
||||
FREE_STRING (msg->session_name);
|
||||
FREE_STRING (msg->information);
|
||||
FREE_STRING (msg->uri);
|
||||
INIT_ARRAY (msg->emails, gchar *);
|
||||
INIT_ARRAY (msg->phones, gchar *);
|
||||
FREE_STRING (msg->connection.nettype);
|
||||
FREE_STRING (msg->connection.addrtype);
|
||||
FREE_STRING (msg->connection.address);
|
||||
msg->connection.ttl = 0;
|
||||
msg->connection.addr_number = 0;
|
||||
INIT_ARRAY (msg->bandwidths, SDPBandwidth);
|
||||
INIT_ARRAY (msg->times, SDPTime);
|
||||
INIT_ARRAY (msg->zones, SDPZone);
|
||||
FREE_STRING (msg->key.type);
|
||||
FREE_STRING (msg->key.data);
|
||||
INIT_ARRAY (msg->attributes, SDPAttribute);
|
||||
INIT_ARRAY (msg->medias, SDPMedia);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_clean (SDPMessage * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
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 RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_free (SDPMessage * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
sdp_message_clean (msg);
|
||||
|
||||
g_free (msg);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
|
||||
RTSPResult
|
||||
sdp_media_new (SDPMedia ** media)
|
||||
{
|
||||
SDPMedia *newmedia;
|
||||
|
||||
if (media == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
newmedia = g_new0 (SDPMedia, 1);
|
||||
|
||||
*media = newmedia;
|
||||
|
||||
return sdp_media_init (newmedia);
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_media_init (SDPMedia * media)
|
||||
{
|
||||
if (media == NULL)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
FREE_STRING (media->media);
|
||||
media->port = 0;
|
||||
media->num_ports = 0;
|
||||
FREE_STRING (media->proto);
|
||||
INIT_ARRAY (media->fmts, gchar *);
|
||||
FREE_STRING (media->information);
|
||||
INIT_ARRAY (media->connections, SDPConnection);
|
||||
INIT_ARRAY (media->bandwidths, SDPBandwidth);
|
||||
FREE_STRING (media->key.type);
|
||||
FREE_STRING (media->key.data);
|
||||
INIT_ARRAY (media->attributes, SDPAttribute);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
DEFINE_STRING_SETTER (version);
|
||||
DEFINE_STRING_GETTER (version);
|
||||
|
||||
RTSPResult
|
||||
sdp_message_set_origin (SDPMessage * 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 RTSP_OK;
|
||||
}
|
||||
|
||||
SDPOrigin *
|
||||
sdp_message_get_origin (SDPMessage * 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);
|
||||
|
||||
RTSPResult
|
||||
sdp_message_set_connection (SDPMessage * 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 RTSP_OK;
|
||||
}
|
||||
|
||||
SDPConnection *
|
||||
sdp_message_get_connection (SDPMessage * msg)
|
||||
{
|
||||
return &msg->connection;
|
||||
}
|
||||
|
||||
DEFINE_ARRAY_LEN (bandwidths);
|
||||
DEFINE_ARRAY_P_GETTER (bandwidth, bandwidths, SDPBandwidth);
|
||||
|
||||
RTSPResult
|
||||
sdp_message_add_bandwidth (SDPMessage * msg, gchar * bwtype, gint bandwidth)
|
||||
{
|
||||
SDPBandwidth bw;
|
||||
|
||||
bw.bwtype = g_strdup (bwtype);
|
||||
bw.bandwidth = bandwidth;
|
||||
|
||||
g_array_append_val (msg->bandwidths, bw);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
DEFINE_ARRAY_LEN (times);
|
||||
DEFINE_ARRAY_P_GETTER (time, times, SDPTime);
|
||||
|
||||
RTSPResult
|
||||
sdp_message_add_time (SDPMessage * msg, gchar * time)
|
||||
{
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
DEFINE_ARRAY_LEN (zones);
|
||||
DEFINE_ARRAY_P_GETTER (zone, zones, SDPZone);
|
||||
RTSPResult
|
||||
sdp_message_add_zone (SDPMessage * msg, gchar * time, gchar * typed_time)
|
||||
{
|
||||
SDPZone zone;
|
||||
|
||||
zone.time = g_strdup (time);
|
||||
zone.typed_time = g_strdup (typed_time);
|
||||
|
||||
g_array_append_val (msg->zones, zone);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_set_key (SDPMessage * msg, gchar * type, gchar * data)
|
||||
{
|
||||
REPLACE_STRING (msg->key.type, type);
|
||||
REPLACE_STRING (msg->key.data, data);
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
SDPKey *
|
||||
sdp_message_get_key (SDPMessage * msg)
|
||||
{
|
||||
return &msg->key;
|
||||
}
|
||||
|
||||
|
||||
DEFINE_ARRAY_LEN (attributes);
|
||||
DEFINE_ARRAY_P_GETTER (attribute, attributes, SDPAttribute);
|
||||
gchar *
|
||||
sdp_message_get_attribute_val (SDPMessage * msg, gchar * key)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < msg->attributes->len; i++) {
|
||||
SDPAttribute *attr;
|
||||
|
||||
attr = &g_array_index (msg->attributes, SDPAttribute, i);
|
||||
if (!strcmp (attr->key, key))
|
||||
return attr->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_add_attribute (SDPMessage * msg, gchar * key, gchar * value)
|
||||
{
|
||||
SDPAttribute attr;
|
||||
|
||||
attr.key = g_strdup (key);
|
||||
attr.value = g_strdup (value);
|
||||
|
||||
g_array_append_val (msg->attributes, attr);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
DEFINE_ARRAY_LEN (medias);
|
||||
DEFINE_ARRAY_P_GETTER (media, medias, SDPMedia);
|
||||
RTSPResult
|
||||
sdp_message_add_media (SDPMessage * msg, SDPMedia * media)
|
||||
{
|
||||
gint len;
|
||||
SDPMedia *nmedia;
|
||||
|
||||
len = msg->medias->len;
|
||||
g_array_set_size (msg->medias, len + 1);
|
||||
nmedia = &g_array_index (msg->medias, SDPMedia, len);
|
||||
|
||||
memcpy (nmedia, media, sizeof (SDPMedia));
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
/* media access */
|
||||
|
||||
RTSPResult
|
||||
sdp_media_add_attribute (SDPMedia * media, gchar * key, gchar * value)
|
||||
{
|
||||
SDPAttribute attr;
|
||||
|
||||
attr.key = g_strdup (key);
|
||||
attr.value = g_strdup (value);
|
||||
|
||||
g_array_append_val (media->attributes, attr);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_media_add_bandwidth (SDPMedia * media, gchar * bwtype, gint bandwidth)
|
||||
{
|
||||
SDPBandwidth bw;
|
||||
|
||||
bw.bwtype = g_strdup (bwtype);
|
||||
bw.bandwidth = bandwidth;
|
||||
|
||||
g_array_append_val (media->bandwidths, bw);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_media_add_format (SDPMedia * media, gchar * format)
|
||||
{
|
||||
gchar *fmt;
|
||||
|
||||
fmt = g_strdup (format);
|
||||
|
||||
g_array_append_val (media->fmts, fmt);
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
gchar *
|
||||
sdp_media_get_attribute_val (SDPMedia * media, gchar * key)
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < media->attributes->len; i++) {
|
||||
SDPAttribute *attr;
|
||||
|
||||
attr = &g_array_index (media->attributes, SDPAttribute, i);
|
||||
if (!strcmp (attr->key, key))
|
||||
return attr->value;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
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_string_del (gchar * dest, gint size, gchar del, gchar ** src)
|
||||
{
|
||||
gint 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;
|
||||
SDPMessage *msg;
|
||||
SDPMedia *media;
|
||||
} SDPContext;
|
||||
|
||||
static gboolean
|
||||
sdp_parse_line (SDPContext * c, gchar type, guint8 * buffer)
|
||||
{
|
||||
gchar str[4096];
|
||||
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_print ("wrong SDP version\n");
|
||||
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':
|
||||
sdp_message_add_email (c->msg, buffer);
|
||||
break;
|
||||
case 'p':
|
||||
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[4096];
|
||||
|
||||
read_string_del (str, sizeof (str), ':', &p);
|
||||
read_string (str2, sizeof (str2), &p);
|
||||
if (c->state == SDP_SESSION)
|
||||
sdp_message_add_bandwidth (c->msg, str, atoi (str2));
|
||||
else
|
||||
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)
|
||||
sdp_message_add_attribute (c->msg, str, p);
|
||||
else
|
||||
sdp_media_add_attribute (c->media, str, p);
|
||||
break;
|
||||
case 'm':
|
||||
{
|
||||
gchar *slash;
|
||||
SDPMedia nmedia = { 0 };
|
||||
|
||||
c->state = SDP_MEDIA;
|
||||
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);
|
||||
sdp_media_add_format (&nmedia, str);
|
||||
} while (*p != '\0');
|
||||
|
||||
g_print ("%p\n", &nmedia);
|
||||
sdp_message_add_media (c->msg, &nmedia);
|
||||
c->media =
|
||||
&g_array_index (c->msg->medias, SDPMedia, c->msg->medias->len - 1);
|
||||
g_print ("%p\n", c->media);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
break;
|
||||
}
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_parse_buffer (guint8 * data, guint size, SDPMessage * msg)
|
||||
{
|
||||
gchar *p;
|
||||
SDPContext c;
|
||||
gchar type;
|
||||
gchar buffer[4096];
|
||||
gint idx = 0;
|
||||
|
||||
if (msg == NULL || data == NULL || size == 0)
|
||||
return RTSP_EINVAL;
|
||||
|
||||
c.state = SDP_SESSION;
|
||||
c.msg = msg;
|
||||
|
||||
p = 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';
|
||||
sdp_parse_line (&c, type, buffer);
|
||||
|
||||
line_done:
|
||||
while (*p != '\n' && *p != '\0')
|
||||
p++;
|
||||
if (*p == '\n')
|
||||
p++;
|
||||
}
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
||||
|
||||
static void
|
||||
print_media (SDPMedia * 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) {
|
||||
gint 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) {
|
||||
gint i;
|
||||
|
||||
g_print (" attributes:\n");
|
||||
for (i = 0; i < media->attributes->len; i++) {
|
||||
SDPAttribute *attr = &g_array_index (media->attributes, SDPAttribute, i);
|
||||
|
||||
g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
RTSPResult
|
||||
sdp_message_dump (SDPMessage * msg)
|
||||
{
|
||||
if (msg == NULL)
|
||||
return RTSP_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) {
|
||||
gint 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) {
|
||||
gint 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) {
|
||||
gint i;
|
||||
|
||||
g_print (" attributes:\n");
|
||||
for (i = 0; i < msg->attributes->len; i++) {
|
||||
SDPAttribute *attr = &g_array_index (msg->attributes, SDPAttribute, i);
|
||||
|
||||
g_print (" attribute '%s' : '%s'\n", attr->key, attr->value);
|
||||
}
|
||||
}
|
||||
if (msg->medias->len > 0) {
|
||||
gint 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, SDPMedia, i));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
return RTSP_OK;
|
||||
}
|
165
gst/rtsp/sdpmessage.h
Normal file
165
gst/rtsp/sdpmessage.h
Normal file
|
@ -0,0 +1,165 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#ifndef __SDP_MESSAGE_H__
|
||||
#define __SDP_MESSAGE_H__
|
||||
|
||||
#include <glib.h>
|
||||
|
||||
#include <rtspdefs.h>
|
||||
|
||||
G_BEGIN_DECLS
|
||||
|
||||
typedef struct {
|
||||
gchar *username;
|
||||
gchar *sess_id;
|
||||
gchar *sess_version;
|
||||
gchar *nettype;
|
||||
gchar *addrtype;
|
||||
gchar *addr;
|
||||
} SDPOrigin;
|
||||
|
||||
typedef struct {
|
||||
gchar *nettype;
|
||||
gchar *addrtype;
|
||||
gchar *address;
|
||||
gint ttl;
|
||||
gint addr_number;
|
||||
} SDPConnection;
|
||||
|
||||
typedef struct {
|
||||
gchar *bwtype;
|
||||
gint bandwidth;
|
||||
} SDPBandwidth;
|
||||
|
||||
typedef struct {
|
||||
gchar *start;
|
||||
gchar *stop;
|
||||
gint n_repeat;
|
||||
gchar *repeat[];
|
||||
} SDPTime;
|
||||
|
||||
typedef struct {
|
||||
gchar *time;
|
||||
gchar *typed_time;
|
||||
} SDPZone;
|
||||
|
||||
typedef struct {
|
||||
gchar *type;
|
||||
gchar *data;
|
||||
} SDPKey;
|
||||
|
||||
typedef struct {
|
||||
gchar *key;
|
||||
gchar *value;
|
||||
} SDPAttribute;
|
||||
|
||||
typedef struct {
|
||||
gchar *media;
|
||||
gint port;
|
||||
gint num_ports;
|
||||
gchar *proto;
|
||||
GArray *fmts;
|
||||
gchar *information;
|
||||
GArray *connections;
|
||||
GArray *bandwidths;
|
||||
SDPKey key;
|
||||
GArray *attributes;
|
||||
} SDPMedia;
|
||||
|
||||
typedef struct {
|
||||
gchar *version;
|
||||
SDPOrigin origin;
|
||||
gchar *session_name;
|
||||
gchar *information;
|
||||
gchar *uri;
|
||||
GArray *emails;
|
||||
GArray *phones;
|
||||
SDPConnection connection;
|
||||
GArray *bandwidths;
|
||||
GArray *times;
|
||||
GArray *zones;
|
||||
SDPKey key;
|
||||
GArray *attributes;
|
||||
GArray *medias;
|
||||
} SDPMessage;
|
||||
|
||||
/* Session descriptions */
|
||||
RTSPResult sdp_message_new (SDPMessage **msg);
|
||||
RTSPResult sdp_message_init (SDPMessage *msg);
|
||||
RTSPResult sdp_message_clean (SDPMessage *msg);
|
||||
RTSPResult sdp_message_free (SDPMessage *msg);
|
||||
|
||||
RTSPResult sdp_message_parse_buffer (guint8 *data, guint size, SDPMessage *msg);
|
||||
|
||||
RTSPResult sdp_message_set_version (SDPMessage *msg, gchar *version);
|
||||
gchar* sdp_message_get_version (SDPMessage *msg);
|
||||
RTSPResult sdp_message_set_origin (SDPMessage *msg, gchar *username, gchar *sess_id,
|
||||
gchar *sess_version, gchar *nettype,
|
||||
gchar *addrtype, gchar *addr);
|
||||
SDPOrigin* sdp_message_get_origin (SDPMessage *msg);
|
||||
RTSPResult sdp_message_set_session_name (SDPMessage *msg, gchar *session_name);
|
||||
gchar* sdp_message_get_session_name (SDPMessage *msg);
|
||||
RTSPResult sdp_message_set_information (SDPMessage *msg, gchar *information);
|
||||
gchar* sdp_message_get_information (SDPMessage *msg);
|
||||
RTSPResult sdp_message_set_uri (SDPMessage *msg, gchar *uri);
|
||||
gchar* sdp_message_get_uri (SDPMessage *msg);
|
||||
gint sdp_message_emails_len (SDPMessage *msg);
|
||||
gchar* sdp_message_get_email (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_email (SDPMessage *msg, gchar *email);
|
||||
gint sdp_message_phones_len (SDPMessage *msg);
|
||||
gchar* sdp_message_get_phone (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_phone (SDPMessage *msg, gchar *phone);
|
||||
RTSPResult sdp_message_set_connection (SDPMessage *msg, gchar *nettype, gchar *addrtype,
|
||||
gchar *address, gint ttl, gint addr_number);
|
||||
SDPConnection* sdp_message_get_connection (SDPMessage *msg);
|
||||
gint sdp_message_bandwidths_len (SDPMessage *msg);
|
||||
SDPBandwidth* sdp_message_get_bandwidth (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_bandwidth (SDPMessage *msg, gchar *bwtype, gint bandwidth);
|
||||
gint sdp_message_times_len (SDPMessage *msg);
|
||||
SDPTime* sdp_message_get_time (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_time (SDPMessage *msg, gchar *time);
|
||||
gint sdp_message_zones_len (SDPMessage *msg);
|
||||
SDPZone* sdp_message_get_zone (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_zone (SDPMessage *msg, gchar *time, gchar *typed_time);
|
||||
RTSPResult sdp_message_set_key (SDPMessage *msg, gchar *type, gchar *data);
|
||||
SDPKey* sdp_message_get_key (SDPMessage *msg);
|
||||
gint sdp_message_attributes_len (SDPMessage *msg);
|
||||
SDPAttribute* sdp_message_get_attribute (SDPMessage *msg, gint i);
|
||||
gchar* sdp_message_get_attribute_val (SDPMessage *msg, gchar *key);
|
||||
RTSPResult sdp_message_add_attribute (SDPMessage *msg, gchar *key, gchar *value);
|
||||
gint sdp_message_medias_len (SDPMessage *msg);
|
||||
SDPMedia* sdp_message_get_media (SDPMessage *msg, gint i);
|
||||
RTSPResult sdp_message_add_media (SDPMessage *msg, SDPMedia *media);
|
||||
|
||||
|
||||
RTSPResult sdp_message_dump (SDPMessage *msg);
|
||||
|
||||
/* Media descriptions */
|
||||
RTSPResult sdp_media_new (SDPMedia **media);
|
||||
RTSPResult sdp_media_init (SDPMedia *media);
|
||||
RTSPResult sdp_media_clean (SDPMedia *media);
|
||||
RTSPResult sdp_media_free (SDPMedia *media);
|
||||
|
||||
gchar* sdp_media_get_attribute_val (SDPMedia *media, gchar *key);
|
||||
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __SDP_MESSAGE_H__ */
|
179
gst/rtsp/test.c
Normal file
179
gst/rtsp/test.c
Normal file
|
@ -0,0 +1,179 @@
|
|||
/* GStreamer
|
||||
* Copyright (C) <2005> 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.
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
|
||||
#include "sdp.h"
|
||||
#include "rtsp.h"
|
||||
|
||||
int
|
||||
main (int argc, gchar * argv[])
|
||||
{
|
||||
RTSPUrl *url;
|
||||
RTSPConnection *conn;
|
||||
RTSPResult res;
|
||||
RTSPMessage request = { 0 };
|
||||
gchar *urlstr;
|
||||
RTSPMessage response = { 0 };
|
||||
SDPMessage sdp = { 0 };
|
||||
|
||||
urlstr = "rtsp://thread:5454/south-rtsp.mp3";
|
||||
|
||||
/* create url */
|
||||
g_print ("parsing url \"%s\"...\n", urlstr);
|
||||
res = rtsp_url_parse (urlstr, &url);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error parsing url \"%s\"\n", urlstr);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
g_print (" url host: %s\n", url->host);
|
||||
g_print (" url port: %d\n", url->port);
|
||||
g_print (" url path: %s\n", url->abspath);
|
||||
|
||||
/* open connection */
|
||||
g_print ("opening connection...\n");
|
||||
res = rtsp_connection_open (url, &conn);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error opening connection to \"%s\"\n", urlstr);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
/* do describe */
|
||||
{
|
||||
res = rtsp_message_init_request (RTSP_DESCRIBE, urlstr, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error creating request\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_add_header (&request, RTSP_HDR_ACCEPT, "application/sdp");
|
||||
|
||||
rtsp_message_dump (&request);
|
||||
|
||||
res = rtsp_connection_send (conn, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error sending request\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = rtsp_connection_receive (conn, &response);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error receiving response\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_dump (&response);
|
||||
}
|
||||
|
||||
/* parse SDP */
|
||||
{
|
||||
guint8 *data;
|
||||
guint size;
|
||||
|
||||
rtsp_message_get_body (&response, &data, &size);
|
||||
|
||||
sdp_message_init (&sdp);
|
||||
sdp_message_parse_buffer (data, size, &sdp);
|
||||
|
||||
sdp_message_dump (&sdp);
|
||||
}
|
||||
|
||||
/* do setup */
|
||||
{
|
||||
gint i;
|
||||
|
||||
for (i = 0; i < sdp_message_medias_len (&sdp); i++) {
|
||||
SDPMedia *media;
|
||||
gchar *setup_url;
|
||||
gchar *control_url;
|
||||
|
||||
media = sdp_message_get_media (&sdp, i);
|
||||
|
||||
g_print ("setup media %d\n", i);
|
||||
control_url = sdp_media_get_attribute_val (media, "control");
|
||||
|
||||
setup_url = g_strdup_printf ("%s/%s", urlstr, control_url);
|
||||
|
||||
g_print ("setup %s\n", setup_url);
|
||||
res = rtsp_message_init_request (RTSP_SETUP, setup_url, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error creating request\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT,
|
||||
//"RTP/AVP/UDP;unicast;client_port=5000-5001,RTP/AVP/UDP;multicast,RTP/AVP/TCP");
|
||||
"RTP/AVP/TCP");
|
||||
rtsp_message_dump (&request);
|
||||
|
||||
res = rtsp_connection_send (conn, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error sending request\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = rtsp_connection_receive (conn, &response);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error receiving response\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_dump (&response);
|
||||
}
|
||||
}
|
||||
/* do play */
|
||||
{
|
||||
res = rtsp_message_init_request (RTSP_PLAY, urlstr, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error creating request\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_dump (&request);
|
||||
|
||||
res = rtsp_connection_send (conn, &request);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error sending request\n");
|
||||
return (-1);
|
||||
}
|
||||
|
||||
res = rtsp_connection_receive (conn, &response);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error receiving response\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_dump (&response);
|
||||
}
|
||||
|
||||
while (TRUE) {
|
||||
res = rtsp_connection_receive (conn, &response);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error receiving response\n");
|
||||
return (-1);
|
||||
}
|
||||
rtsp_message_dump (&response);
|
||||
}
|
||||
|
||||
/* close connection */
|
||||
g_print ("closing connection...\n");
|
||||
res = rtsp_connection_close (conn);
|
||||
if (res != RTSP_OK) {
|
||||
g_print ("error closing connection to \"%s\"\n", urlstr);
|
||||
return (-1);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
Loading…
Reference in a new issue