mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-30 12:10:37 +00:00
01bbdd6bdf
This is useful and in most cases someone had put arbitrary markup into the docs, misspelled xref'ed symbols, forgot to add stuff to the docs etc..
716 lines
21 KiB
C
716 lines
21 KiB
C
/* GStreamer
|
|
* Copyright (C) <2005,2006,2007> Wim Taymans <wim@fluendo.com>
|
|
* <2007> Peter Kjellerstedt <pkj at axis com>
|
|
*
|
|
* This library is free software; you can redistribute it and/or
|
|
* modify it under the terms of the GNU Library General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 2 of the License, or (at your option) any later version.
|
|
*
|
|
* This library is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
* Library General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU Library General Public
|
|
* License along with this library; if not, write to the
|
|
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
|
|
* Boston, MA 02111-1307, USA.
|
|
*/
|
|
/*
|
|
* Unless otherwise indicated, Source Code is licensed under MIT license.
|
|
* See further explanation attached in License Statement (distributed in the file
|
|
* LICENSE).
|
|
*
|
|
* Permission is hereby granted, free of charge, to any person obtaining a copy of
|
|
* this software and associated documentation files (the "Software"), to deal in
|
|
* the Software without restriction, including without limitation the rights to
|
|
* use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
|
|
* of the Software, and to permit persons to whom the Software is furnished to do
|
|
* so, subject to the following conditions:
|
|
*
|
|
* The above copyright notice and this permission notice shall be included in all
|
|
* copies or substantial portions of the Software.
|
|
*
|
|
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
* SOFTWARE.
|
|
*/
|
|
|
|
/**
|
|
* SECTION:gstrtsptransport
|
|
* @short_description: dealing with RTSP transports
|
|
*
|
|
* Provides helper functions to deal with RTSP transport strings.
|
|
*
|
|
* Last reviewed on 2007-07-25 (0.10.14)
|
|
*/
|
|
|
|
#include <string.h>
|
|
#include <stdlib.h>
|
|
|
|
#include "gstrtsptransport.h"
|
|
|
|
#define MAX_MANAGERS 2
|
|
|
|
typedef enum
|
|
{
|
|
RTSP_TRANSPORT_DELIVERY = 1 << 0, /* multicast | unicast */
|
|
RTSP_TRANSPORT_DESTINATION = 1 << 1,
|
|
RTSP_TRANSPORT_SOURCE = 1 << 2,
|
|
RTSP_TRANSPORT_INTERLEAVED = 1 << 3,
|
|
RTSP_TRANSPORT_APPEND = 1 << 4,
|
|
RTSP_TRANSPORT_TTL = 1 << 5,
|
|
RTSP_TRANSPORT_LAYERS = 1 << 6,
|
|
RTSP_TRANSPORT_PORT = 1 << 7,
|
|
RTSP_TRANSPORT_CLIENT_PORT = 1 << 8,
|
|
RTSP_TRANSPORT_SERVER_PORT = 1 << 9,
|
|
RTSP_TRANSPORT_SSRC = 1 << 10,
|
|
RTSP_TRANSPORT_MODE = 1 << 11,
|
|
} RTSPTransportParameter;
|
|
|
|
typedef struct
|
|
{
|
|
const gchar *name;
|
|
const GstRTSPTransMode mode;
|
|
const gchar *gst_mime;
|
|
const gchar *manager[MAX_MANAGERS];
|
|
} GstRTSPTransMap;
|
|
|
|
static const GstRTSPTransMap transports[] = {
|
|
{"rtp", GST_RTSP_TRANS_RTP, "application/x-rtp", {"gstrtpbin", "rtpdec"}},
|
|
{"x-real-rdt", GST_RTSP_TRANS_RDT, "application/x-rdt", {"rdtmanager", NULL}},
|
|
{"x-pn-tng", GST_RTSP_TRANS_RDT, "application/x-rdt", {"rdtmanager", NULL}},
|
|
{NULL, GST_RTSP_TRANS_UNKNOWN, NULL, {NULL, NULL}}
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
const gchar *name;
|
|
const GstRTSPProfile profile;
|
|
} RTSPProfileMap;
|
|
|
|
static const RTSPProfileMap profiles[] = {
|
|
{"avp", GST_RTSP_PROFILE_AVP},
|
|
{"savp", GST_RTSP_PROFILE_SAVP},
|
|
{NULL, GST_RTSP_PROFILE_UNKNOWN}
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
const gchar *name;
|
|
const GstRTSPLowerTrans ltrans;
|
|
} RTSPLTransMap;
|
|
|
|
static const RTSPLTransMap ltrans[] = {
|
|
{"udp", GST_RTSP_LOWER_TRANS_UDP},
|
|
{"mcast", GST_RTSP_LOWER_TRANS_UDP_MCAST},
|
|
{"tcp", GST_RTSP_LOWER_TRANS_TCP},
|
|
{NULL, GST_RTSP_LOWER_TRANS_UNKNOWN}
|
|
};
|
|
|
|
|
|
GType
|
|
gst_rtsp_lower_trans_get_type (void)
|
|
{
|
|
static volatile gsize rtsp_lower_trans_type = 0;
|
|
static const GFlagsValue rtsp_lower_trans[] = {
|
|
{GST_RTSP_LOWER_TRANS_UDP, "GST_RTSP_LOWER_TRANS_UDP", "udp-unicast"},
|
|
{GST_RTSP_LOWER_TRANS_UDP_MCAST, "GST_RTSP_LOWER_TRANS_UDP_MCAST",
|
|
"udp-multicast"},
|
|
{GST_RTSP_LOWER_TRANS_TCP, "GST_RTSP_LOWER_TRANS_TCP", "tcp"},
|
|
{GST_RTSP_LOWER_TRANS_HTTP, "GST_RTSP_LOWER_TRANS_HTTP", "http"},
|
|
{0, NULL, NULL},
|
|
};
|
|
|
|
if (g_once_init_enter (&rtsp_lower_trans_type)) {
|
|
GType tmp = g_flags_register_static ("GstRTSPLowerTrans", rtsp_lower_trans);
|
|
g_once_init_leave (&rtsp_lower_trans_type, tmp);
|
|
}
|
|
|
|
return (GType) rtsp_lower_trans_type;
|
|
}
|
|
|
|
#define RTSP_TRANSPORT_PARAMETER_IS_UNIQUE(param) \
|
|
G_STMT_START { \
|
|
if ((transport_params & (param)) != 0) \
|
|
goto invalid_transport; \
|
|
transport_params |= (param); \
|
|
} G_STMT_END
|
|
|
|
/**
|
|
* gst_rtsp_transport_new:
|
|
* @transport: location to hold the new #GstRTSPTransport
|
|
*
|
|
* Allocate a new initialized #GstRTSPTransport. Use gst_rtsp_transport_free()
|
|
* after usage.
|
|
*
|
|
* Returns: a #GstRTSPResult.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_new (GstRTSPTransport ** transport)
|
|
{
|
|
GstRTSPTransport *trans;
|
|
|
|
g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
|
|
|
|
trans = g_new0 (GstRTSPTransport, 1);
|
|
|
|
*transport = trans;
|
|
|
|
return gst_rtsp_transport_init (trans);
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_transport_init:
|
|
* @transport: a #GstRTSPTransport
|
|
*
|
|
* Initialize @transport so that it can be used.
|
|
*
|
|
* Returns: #GST_RTSP_OK.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_init (GstRTSPTransport * transport)
|
|
{
|
|
g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
|
|
|
|
g_free (transport->destination);
|
|
g_free (transport->source);
|
|
|
|
memset (transport, 0, sizeof (GstRTSPTransport));
|
|
|
|
transport->trans = GST_RTSP_TRANS_RTP;
|
|
transport->profile = GST_RTSP_PROFILE_AVP;
|
|
transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
|
|
transport->mode_play = TRUE;
|
|
transport->mode_record = FALSE;
|
|
transport->interleaved.min = -1;
|
|
transport->interleaved.max = -1;
|
|
transport->port.min = -1;
|
|
transport->port.max = -1;
|
|
transport->client_port.min = -1;
|
|
transport->client_port.max = -1;
|
|
transport->server_port.min = -1;
|
|
transport->server_port.max = -1;
|
|
|
|
return GST_RTSP_OK;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_transport_get_mime:
|
|
* @trans: a #GstRTSPTransMode
|
|
* @mime: location to hold the result
|
|
*
|
|
* Get the mime type of the transport mode @trans. This mime type is typically
|
|
* used to generate #GstCaps on buffers.
|
|
*
|
|
* Returns: #GST_RTSP_OK.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_get_mime (GstRTSPTransMode trans, const gchar ** mime)
|
|
{
|
|
gint i;
|
|
|
|
g_return_val_if_fail (mime != NULL, GST_RTSP_EINVAL);
|
|
|
|
for (i = 0; transports[i].name; i++)
|
|
if (transports[i].mode == trans)
|
|
break;
|
|
*mime = transports[i].gst_mime;
|
|
|
|
return GST_RTSP_OK;
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_transport_get_manager:
|
|
* @trans: a #GstRTSPTransMode
|
|
* @manager: location to hold the result
|
|
* @option: option index.
|
|
*
|
|
* Get the #GstElement that can handle the buffers transported over @trans.
|
|
*
|
|
* It is possible that there are several managers available, use @option to
|
|
* selected one.
|
|
*
|
|
* @manager will contain an element name or #NULL when no manager is
|
|
* needed/available for @trans.
|
|
*
|
|
* Returns: #GST_RTSP_OK.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_get_manager (GstRTSPTransMode trans, const gchar ** manager,
|
|
guint option)
|
|
{
|
|
gint i;
|
|
|
|
g_return_val_if_fail (manager != NULL, GST_RTSP_EINVAL);
|
|
|
|
for (i = 0; transports[i].name; i++)
|
|
if (transports[i].mode == trans)
|
|
break;
|
|
|
|
if (option < MAX_MANAGERS)
|
|
*manager = transports[i].manager[option];
|
|
else
|
|
*manager = NULL;
|
|
|
|
return GST_RTSP_OK;
|
|
}
|
|
|
|
static void
|
|
parse_mode (GstRTSPTransport * transport, const gchar * str)
|
|
{
|
|
transport->mode_play = (strstr (str, "play") != NULL);
|
|
transport->mode_record = (strstr (str, "record") != NULL);
|
|
}
|
|
|
|
static gboolean
|
|
check_range (const gchar * str, gchar ** tmp, gint * range)
|
|
{
|
|
glong range_val;
|
|
|
|
range_val = strtol (str, tmp, 10);
|
|
if (range_val >= G_MININT && range_val <= G_MAXINT) {
|
|
*range = range_val;
|
|
return TRUE;
|
|
} else {
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static gboolean
|
|
parse_range (const gchar * str, GstRTSPRange * range)
|
|
{
|
|
gchar *minus;
|
|
gchar *tmp;
|
|
|
|
/* even though strtol() allows white space, plus and minus in front of
|
|
* the number, we do not allow it
|
|
*/
|
|
if (g_ascii_isspace (*str) || *str == '+' || *str == '-')
|
|
goto invalid_range;
|
|
|
|
minus = strstr (str, "-");
|
|
if (minus) {
|
|
if (g_ascii_isspace (minus[1]) || minus[1] == '+' || minus[1] == '-')
|
|
goto invalid_range;
|
|
|
|
if (!check_range (str, &tmp, &range->min) || str == tmp || tmp != minus)
|
|
goto invalid_range;
|
|
|
|
if (!check_range (minus + 1, &tmp, &range->max) || (*tmp && *tmp != ';'))
|
|
goto invalid_range;
|
|
} else {
|
|
if (!check_range (str, &tmp, &range->min) || str == tmp ||
|
|
(*tmp && *tmp != ';'))
|
|
goto invalid_range;
|
|
|
|
range->max = -1;
|
|
}
|
|
|
|
return TRUE;
|
|
|
|
invalid_range:
|
|
{
|
|
range->min = -1;
|
|
range->max = -1;
|
|
return FALSE;
|
|
}
|
|
}
|
|
|
|
static gchar *
|
|
range_as_text (const GstRTSPRange * range)
|
|
{
|
|
if (range->min < 0)
|
|
return NULL;
|
|
else if (range->max < 0)
|
|
return g_strdup_printf ("%d", range->min);
|
|
else
|
|
return g_strdup_printf ("%d-%d", range->min, range->max);
|
|
}
|
|
|
|
static const gchar *
|
|
rtsp_transport_mode_as_text (const GstRTSPTransport * transport)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; transports[i].name; i++)
|
|
if (transports[i].mode == transport->trans)
|
|
return transports[i].name;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const gchar *
|
|
rtsp_transport_profile_as_text (const GstRTSPTransport * transport)
|
|
{
|
|
gint i;
|
|
|
|
for (i = 0; profiles[i].name; i++)
|
|
if (profiles[i].profile == transport->profile)
|
|
return profiles[i].name;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
static const gchar *
|
|
rtsp_transport_ltrans_as_text (const GstRTSPTransport * transport)
|
|
{
|
|
gint i;
|
|
|
|
/* need to special case GST_RTSP_LOWER_TRANS_UDP_MCAST */
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
|
|
return "udp";
|
|
|
|
for (i = 0; ltrans[i].name; i++)
|
|
if (ltrans[i].ltrans == transport->lower_transport)
|
|
return ltrans[i].name;
|
|
|
|
return NULL;
|
|
}
|
|
|
|
#define IS_VALID_PORT_RANGE(range) \
|
|
(range.min >= 0 && range.min < 65536 && range.max < 65536)
|
|
|
|
#define IS_VALID_INTERLEAVE_RANGE(range) \
|
|
(range.min >= 0 && range.min < 256 && range.max < 256)
|
|
|
|
/**
|
|
* gst_rtsp_transport_parse:
|
|
* @str: a transport string
|
|
* @transport: a #GstRTSPTransport
|
|
*
|
|
* Parse the RTSP transport string @str into @transport.
|
|
*
|
|
* Returns: a #GstRTSPResult.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_parse (const gchar * str, GstRTSPTransport * transport)
|
|
{
|
|
gchar **split, *down, **transp = NULL;
|
|
guint transport_params = 0;
|
|
gint i, count;
|
|
|
|
g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
|
|
g_return_val_if_fail (str != NULL, GST_RTSP_EINVAL);
|
|
|
|
gst_rtsp_transport_init (transport);
|
|
|
|
/* case insensitive */
|
|
down = g_ascii_strdown (str, -1);
|
|
|
|
split = g_strsplit (down, ";", 0);
|
|
g_free (down);
|
|
|
|
/* First field contains the transport/profile/lower_transport */
|
|
if (split[0] == NULL)
|
|
goto invalid_transport;
|
|
|
|
transp = g_strsplit (split[0], "/", 0);
|
|
|
|
if (transp[0] == NULL || transp[1] == NULL)
|
|
goto invalid_transport;
|
|
|
|
for (i = 0; transports[i].name; i++)
|
|
if (strcmp (transp[0], transports[i].name) == 0)
|
|
break;
|
|
transport->trans = transports[i].mode;
|
|
|
|
if (transport->trans != GST_RTSP_TRANS_RDT) {
|
|
for (i = 0; profiles[i].name; i++)
|
|
if (strcmp (transp[1], profiles[i].name) == 0)
|
|
break;
|
|
transport->profile = profiles[i].profile;
|
|
count = 2;
|
|
} else {
|
|
/* RDT has transport/lower_transport */
|
|
transport->profile = GST_RTSP_PROFILE_AVP;
|
|
count = 1;
|
|
}
|
|
|
|
if (transp[count] != NULL) {
|
|
for (i = 0; ltrans[i].name; i++)
|
|
if (strcmp (transp[count], ltrans[i].name) == 0)
|
|
break;
|
|
transport->lower_transport = ltrans[i].ltrans;
|
|
} else {
|
|
/* specifying the lower transport is optional */
|
|
if (transport->trans == GST_RTSP_TRANS_RTP &&
|
|
transport->profile == GST_RTSP_PROFILE_AVP)
|
|
transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
|
|
else
|
|
transport->lower_transport = GST_RTSP_LOWER_TRANS_UNKNOWN;
|
|
}
|
|
|
|
g_strfreev (transp);
|
|
transp = NULL;
|
|
|
|
if (transport->trans == GST_RTSP_TRANS_UNKNOWN ||
|
|
transport->profile == GST_RTSP_PROFILE_UNKNOWN ||
|
|
transport->lower_transport == GST_RTSP_LOWER_TRANS_UNKNOWN)
|
|
goto unsupported_transport;
|
|
|
|
i = 1;
|
|
while (split[i]) {
|
|
if (strcmp (split[i], "multicast") == 0) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP)
|
|
goto invalid_transport;
|
|
transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP_MCAST;
|
|
} else if (strcmp (split[i], "unicast") == 0) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DELIVERY);
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
|
|
transport->lower_transport = GST_RTSP_LOWER_TRANS_UDP;
|
|
} else if (g_str_has_prefix (split[i], "destination=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_DESTINATION);
|
|
transport->destination = g_strdup (split[i] + 12);
|
|
} else if (g_str_has_prefix (split[i], "source=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SOURCE);
|
|
transport->source = g_strdup (split[i] + 7);
|
|
} else if (g_str_has_prefix (split[i], "layers=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_LAYERS);
|
|
transport->layers = strtoul (split[i] + 7, NULL, 10);
|
|
} else if (g_str_has_prefix (split[i], "mode=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_MODE);
|
|
parse_mode (transport, split[i] + 5);
|
|
if (!transport->mode_play && !transport->mode_record)
|
|
goto invalid_transport;
|
|
} else if (strcmp (split[i], "append") == 0) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_APPEND);
|
|
transport->append = TRUE;
|
|
} else if (g_str_has_prefix (split[i], "interleaved=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_INTERLEAVED);
|
|
parse_range (split[i] + 12, &transport->interleaved);
|
|
if (!IS_VALID_INTERLEAVE_RANGE (transport->interleaved))
|
|
goto invalid_transport;
|
|
} else if (g_str_has_prefix (split[i], "ttl=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_TTL);
|
|
transport->ttl = strtoul (split[i] + 4, NULL, 10);
|
|
if (transport->ttl >= 256)
|
|
goto invalid_transport;
|
|
} else if (g_str_has_prefix (split[i], "port=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_PORT);
|
|
if (parse_range (split[i] + 5, &transport->port)) {
|
|
if (!IS_VALID_PORT_RANGE (transport->port))
|
|
goto invalid_transport;
|
|
}
|
|
} else if (g_str_has_prefix (split[i], "client_port=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_CLIENT_PORT);
|
|
if (parse_range (split[i] + 12, &transport->client_port)) {
|
|
if (!IS_VALID_PORT_RANGE (transport->client_port))
|
|
goto invalid_transport;
|
|
}
|
|
} else if (g_str_has_prefix (split[i], "server_port=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SERVER_PORT);
|
|
if (parse_range (split[i] + 12, &transport->server_port)) {
|
|
if (!IS_VALID_PORT_RANGE (transport->server_port))
|
|
goto invalid_transport;
|
|
}
|
|
} else if (g_str_has_prefix (split[i], "ssrc=")) {
|
|
RTSP_TRANSPORT_PARAMETER_IS_UNIQUE (RTSP_TRANSPORT_SSRC);
|
|
transport->ssrc = strtoul (split[i] + 5, NULL, 16);
|
|
} else {
|
|
/* unknown field... */
|
|
g_warning ("unknown transport field \"%s\"", split[i]);
|
|
}
|
|
i++;
|
|
}
|
|
g_strfreev (split);
|
|
|
|
return GST_RTSP_OK;
|
|
|
|
unsupported_transport:
|
|
{
|
|
g_strfreev (split);
|
|
return GST_RTSP_ERROR;
|
|
}
|
|
invalid_transport:
|
|
{
|
|
g_strfreev (transp);
|
|
g_strfreev (split);
|
|
return GST_RTSP_EINVAL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_transport_as_text:
|
|
* @transport: a #GstRTSPTransport
|
|
*
|
|
* Convert @transport into a string that can be used to signal the transport in
|
|
* an RTSP SETUP response.
|
|
*
|
|
* Returns: a string describing the RTSP transport or #NULL when the transport
|
|
* is invalid.
|
|
*/
|
|
gchar *
|
|
gst_rtsp_transport_as_text (GstRTSPTransport * transport)
|
|
{
|
|
GPtrArray *strs;
|
|
gchar *res;
|
|
const gchar *tmp;
|
|
|
|
g_return_val_if_fail (transport != NULL, NULL);
|
|
|
|
strs = g_ptr_array_new ();
|
|
|
|
/* add the transport specifier */
|
|
if ((tmp = rtsp_transport_mode_as_text (transport)) == NULL)
|
|
goto invalid_transport;
|
|
g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
|
|
|
|
g_ptr_array_add (strs, g_strdup ("/"));
|
|
|
|
if ((tmp = rtsp_transport_profile_as_text (transport)) == NULL)
|
|
goto invalid_transport;
|
|
g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
|
|
|
|
if (transport->trans != GST_RTSP_TRANS_RTP ||
|
|
transport->profile != GST_RTSP_PROFILE_AVP ||
|
|
transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP) {
|
|
g_ptr_array_add (strs, g_strdup ("/"));
|
|
|
|
if ((tmp = rtsp_transport_ltrans_as_text (transport)) == NULL)
|
|
goto invalid_transport;
|
|
|
|
g_ptr_array_add (strs, g_ascii_strup (tmp, -1));
|
|
}
|
|
|
|
/*
|
|
* the order of the following parameters is the same as the one specified in
|
|
* RFC 2326 to please some weird RTSP clients that require it
|
|
*/
|
|
|
|
/* add the unicast/multicast parameter */
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST)
|
|
g_ptr_array_add (strs, g_strdup (";multicast"));
|
|
else
|
|
g_ptr_array_add (strs, g_strdup (";unicast"));
|
|
|
|
/* add the destination parameter */
|
|
if (transport->destination != NULL) {
|
|
g_ptr_array_add (strs, g_strdup (";destination="));
|
|
g_ptr_array_add (strs, g_strdup (transport->destination));
|
|
}
|
|
|
|
/* add the source parameter */
|
|
if (transport->source != NULL) {
|
|
g_ptr_array_add (strs, g_strdup (";source="));
|
|
g_ptr_array_add (strs, g_strdup (transport->source));
|
|
}
|
|
|
|
/* add the interleaved parameter */
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_TCP &&
|
|
transport->interleaved.min >= 0) {
|
|
if (transport->interleaved.min < 256 && transport->interleaved.max < 256) {
|
|
g_ptr_array_add (strs, g_strdup (";interleaved="));
|
|
g_ptr_array_add (strs, range_as_text (&transport->interleaved));
|
|
} else
|
|
goto invalid_transport;
|
|
}
|
|
|
|
/* add the append parameter */
|
|
if (transport->mode_record && transport->append)
|
|
g_ptr_array_add (strs, g_strdup (";append"));
|
|
|
|
/* add the ttl parameter */
|
|
if (transport->lower_transport == GST_RTSP_LOWER_TRANS_UDP_MCAST &&
|
|
transport->ttl != 0) {
|
|
if (transport->ttl < 256) {
|
|
g_ptr_array_add (strs, g_strdup (";ttl="));
|
|
g_ptr_array_add (strs, g_strdup_printf ("%u", transport->ttl));
|
|
} else
|
|
goto invalid_transport;
|
|
}
|
|
|
|
/* add the layers parameter */
|
|
if (transport->layers != 0) {
|
|
g_ptr_array_add (strs, g_strdup (";layers="));
|
|
g_ptr_array_add (strs, g_strdup_printf ("%u", transport->layers));
|
|
}
|
|
|
|
/* add the port parameter */
|
|
if (transport->lower_transport != GST_RTSP_LOWER_TRANS_TCP) {
|
|
if (transport->trans == GST_RTSP_TRANS_RTP && transport->port.min >= 0) {
|
|
if (transport->port.min < 65536 && transport->port.max < 65536) {
|
|
g_ptr_array_add (strs, g_strdup (";port="));
|
|
g_ptr_array_add (strs, range_as_text (&transport->port));
|
|
} else
|
|
goto invalid_transport;
|
|
}
|
|
|
|
/* add the client_port parameter */
|
|
if (transport->trans == GST_RTSP_TRANS_RTP
|
|
&& transport->client_port.min >= 0) {
|
|
if (transport->client_port.min < 65536
|
|
&& transport->client_port.max < 65536) {
|
|
g_ptr_array_add (strs, g_strdup (";client_port="));
|
|
g_ptr_array_add (strs, range_as_text (&transport->client_port));
|
|
} else
|
|
goto invalid_transport;
|
|
}
|
|
|
|
/* add the server_port parameter */
|
|
if (transport->trans == GST_RTSP_TRANS_RTP
|
|
&& transport->server_port.min >= 0) {
|
|
if (transport->server_port.min < 65536
|
|
&& transport->server_port.max < 65536) {
|
|
g_ptr_array_add (strs, g_strdup (";server_port="));
|
|
g_ptr_array_add (strs, range_as_text (&transport->server_port));
|
|
} else
|
|
goto invalid_transport;
|
|
}
|
|
}
|
|
|
|
/* add the ssrc parameter */
|
|
if (transport->lower_transport != GST_RTSP_LOWER_TRANS_UDP_MCAST &&
|
|
transport->ssrc != 0) {
|
|
g_ptr_array_add (strs, g_strdup (";ssrc="));
|
|
g_ptr_array_add (strs, g_strdup_printf ("%08X", transport->ssrc));
|
|
}
|
|
|
|
/* add the mode parameter */
|
|
if (transport->mode_play && transport->mode_record)
|
|
g_ptr_array_add (strs, g_strdup (";mode=\"PLAY,RECORD\""));
|
|
else if (transport->mode_record)
|
|
g_ptr_array_add (strs, g_strdup (";mode=\"RECORD\""));
|
|
else if (transport->mode_play)
|
|
g_ptr_array_add (strs, g_strdup (";mode=\"PLAY\""));
|
|
|
|
/* add a terminating NULL */
|
|
g_ptr_array_add (strs, NULL);
|
|
|
|
res = g_strjoinv (NULL, (gchar **) strs->pdata);
|
|
g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
|
|
|
|
return res;
|
|
|
|
invalid_transport:
|
|
{
|
|
g_ptr_array_add (strs, NULL);
|
|
g_strfreev ((gchar **) g_ptr_array_free (strs, FALSE));
|
|
return NULL;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* gst_rtsp_transport_free:
|
|
* @transport: a #GstRTSPTransport
|
|
*
|
|
* Free the memory used by @transport.
|
|
*
|
|
* Returns: #GST_RTSP_OK.
|
|
*/
|
|
GstRTSPResult
|
|
gst_rtsp_transport_free (GstRTSPTransport * transport)
|
|
{
|
|
g_return_val_if_fail (transport != NULL, GST_RTSP_EINVAL);
|
|
|
|
gst_rtsp_transport_init (transport);
|
|
g_free (transport);
|
|
|
|
return GST_RTSP_OK;
|
|
}
|