Commit 6f0ea358 authored by Wim Taymans's avatar Wim Taymans

Ported to 0.9.

Original commit message from CVS:
Ported to 0.9.
Set up transports, init UDP ports, init RTP session managers.
parent 6cacd6f6
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:
......
Makefile
Makefile.in
*.o
*.lo
*.la
.deps
.libs
test
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
/* 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)
/* 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__ */
This diff is collapsed.
/* 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__ */
/* 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__ */
/* 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;
}
}
/* GStreamer
* Copyright (C) <2005> Wim Taymans <wim@fluendo.com>