mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2024-12-24 09:10:36 +00:00
gst/rtsp/: Allow url to be NULL to be able to use it for server connections.
Original commit message from CVS: Patch by: Peter Kjellerstedt <pkj at axis com> * gst/rtsp/COPYING.MIT: * gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream), (gst_rtspsrc_stream_free), (gst_rtspsrc_cleanup), (gst_rtspsrc_alloc_udp_ports), (pad_unblocked), (pad_blocked), (gst_rtspsrc_stream_configure_transport), (gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved), (gst_rtspsrc_loop_udp), (gst_rtspsrc_send), (gst_rtspsrc_parse_methods), (gst_rtspsrc_create_transports_string), (gst_rtspsrc_prepare_transports), (gst_rtspsrc_setup_streams), (gst_rtspsrc_open), (gst_rtspsrc_close): * gst/rtsp/gstrtspsrc.h: * gst/rtsp/rtspconnection.c: (rtsp_connection_create), (rtsp_connection_connect), (rtsp_connection_send), (read_line), (parse_request_line), (parse_line), (rtsp_connection_read), (rtsp_connection_close): * gst/rtsp/rtspdefs.c: (rtsp_init_status), (rtsp_strresult), (rtsp_method_as_text), (rtsp_header_as_text), (rtsp_status_as_text), (rtsp_find_header_field), (rtsp_find_method): * gst/rtsp/rtspdefs.h: * gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send), (rtsp_ext_wms_configure_stream): * gst/rtsp/rtspmessage.c: (rtsp_message_new), (rtsp_message_init), (rtsp_message_new_request), (rtsp_message_init_request), (rtsp_message_new_response), (rtsp_message_init_response), (rtsp_message_init_data), (rtsp_message_unset), (rtsp_message_free), (rtsp_message_add_header), (rtsp_message_get_header), (rtsp_message_set_body), (rtsp_message_get_body), (dump_mem), (rtsp_message_dump): * gst/rtsp/rtspmessage.h: * gst/rtsp/sdpmessage.c: (sdp_message_get_attribute_val_n), (sdp_media_get_attribute_val_n), (read_string), (read_string_del), (sdp_parse_line), (sdp_message_parse_buffer), (print_media), (sdp_message_dump): Allow url to be NULL to be able to use it for server connections. Can now send responses as well as requests. No longer hangs in an endless loop if EOF is received. Can now convert a status code to a text string. Return RTSP_HDR_INVALID for unknown headers. Return RTSP_INVALID for unknown methods. Copy CSeq and Session headers from the request. Only free memory corresponding to the currently set message type. Added const to function arguments as appropriate. Avoid a compiler warning when initializing nmedia. Use guint rather than gint to avoid compiler warnings. Fix crasher in wms extension. Factor out stream setup from open_connection. Delay activation of streams when actual data is received from the server, this prepares us to do proper protocol switching. Added new license. Fixes #380895.
This commit is contained in:
parent
8f7c1775d9
commit
12ab127d12
11 changed files with 720 additions and 317 deletions
58
ChangeLog
58
ChangeLog
|
@ -1,3 +1,61 @@
|
||||||
|
2007-01-10 Wim Taymans <wim@fluendo.com>
|
||||||
|
|
||||||
|
Patch by: Peter Kjellerstedt <pkj at axis com>
|
||||||
|
|
||||||
|
* gst/rtsp/COPYING.MIT:
|
||||||
|
* gst/rtsp/gstrtspsrc.c: (gst_rtspsrc_create_stream),
|
||||||
|
(gst_rtspsrc_stream_free), (gst_rtspsrc_cleanup),
|
||||||
|
(gst_rtspsrc_alloc_udp_ports), (pad_unblocked), (pad_blocked),
|
||||||
|
(gst_rtspsrc_stream_configure_transport),
|
||||||
|
(gst_rtspsrc_activate_streams), (gst_rtspsrc_loop_interleaved),
|
||||||
|
(gst_rtspsrc_loop_udp), (gst_rtspsrc_send),
|
||||||
|
(gst_rtspsrc_parse_methods),
|
||||||
|
(gst_rtspsrc_create_transports_string),
|
||||||
|
(gst_rtspsrc_prepare_transports), (gst_rtspsrc_setup_streams),
|
||||||
|
(gst_rtspsrc_open), (gst_rtspsrc_close):
|
||||||
|
* gst/rtsp/gstrtspsrc.h:
|
||||||
|
* gst/rtsp/rtspconnection.c: (rtsp_connection_create),
|
||||||
|
(rtsp_connection_connect), (rtsp_connection_send), (read_line),
|
||||||
|
(parse_request_line), (parse_line), (rtsp_connection_read),
|
||||||
|
(rtsp_connection_close):
|
||||||
|
* gst/rtsp/rtspdefs.c: (rtsp_init_status), (rtsp_strresult),
|
||||||
|
(rtsp_method_as_text), (rtsp_header_as_text),
|
||||||
|
(rtsp_status_as_text), (rtsp_find_header_field),
|
||||||
|
(rtsp_find_method):
|
||||||
|
* gst/rtsp/rtspdefs.h:
|
||||||
|
* gst/rtsp/rtspextwms.c: (rtsp_ext_wms_after_send),
|
||||||
|
(rtsp_ext_wms_configure_stream):
|
||||||
|
* gst/rtsp/rtspmessage.c: (rtsp_message_new), (rtsp_message_init),
|
||||||
|
(rtsp_message_new_request), (rtsp_message_init_request),
|
||||||
|
(rtsp_message_new_response), (rtsp_message_init_response),
|
||||||
|
(rtsp_message_init_data), (rtsp_message_unset),
|
||||||
|
(rtsp_message_free), (rtsp_message_add_header),
|
||||||
|
(rtsp_message_get_header), (rtsp_message_set_body),
|
||||||
|
(rtsp_message_get_body), (dump_mem), (rtsp_message_dump):
|
||||||
|
* gst/rtsp/rtspmessage.h:
|
||||||
|
* gst/rtsp/sdpmessage.c: (sdp_message_get_attribute_val_n),
|
||||||
|
(sdp_media_get_attribute_val_n), (read_string), (read_string_del),
|
||||||
|
(sdp_parse_line), (sdp_message_parse_buffer), (print_media),
|
||||||
|
(sdp_message_dump):
|
||||||
|
Allow url to be NULL to be able to use it for server connections.
|
||||||
|
Can now send responses as well as requests.
|
||||||
|
No longer hangs in an endless loop if EOF is received.
|
||||||
|
Can now convert a status code to a text string.
|
||||||
|
Return RTSP_HDR_INVALID for unknown headers.
|
||||||
|
Return RTSP_INVALID for unknown methods.
|
||||||
|
Copy CSeq and Session headers from the request.
|
||||||
|
Only free memory corresponding to the currently set message type.
|
||||||
|
Added const to function arguments as appropriate.
|
||||||
|
Avoid a compiler warning when initializing nmedia.
|
||||||
|
Use guint rather than gint to avoid compiler warnings.
|
||||||
|
Fix crasher in wms extension.
|
||||||
|
Factor out stream setup from open_connection.
|
||||||
|
Delay activation of streams when actual data is received from the
|
||||||
|
server, this prepares us to do proper protocol switching.
|
||||||
|
Added new license.
|
||||||
|
Fixes #380895.
|
||||||
|
|
||||||
|
|
||||||
2007-01-10 Tim-Philipp Müller <tim at centricular dot net>
|
2007-01-10 Tim-Philipp Müller <tim at centricular dot net>
|
||||||
|
|
||||||
Patch by: Sebastian Dröge <slomo ubuntu com>
|
Patch by: Sebastian Dröge <slomo ubuntu com>
|
||||||
|
|
23
gst/rtsp/COPYING.MIT
Normal file
23
gst/rtsp/COPYING.MIT
Normal file
|
@ -0,0 +1,23 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
|
@ -95,9 +95,8 @@
|
||||||
#include "gstrtspsrc.h"
|
#include "gstrtspsrc.h"
|
||||||
#include "sdp.h"
|
#include "sdp.h"
|
||||||
|
|
||||||
#if 0
|
/* define for experimental real support */
|
||||||
#define WITH_EXT_REAL
|
#undef WITH_EXT_REAL
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "rtspextwms.h"
|
#include "rtspextwms.h"
|
||||||
#ifdef WITH_EXT_REAL
|
#ifdef WITH_EXT_REAL
|
||||||
|
@ -165,6 +164,11 @@ gst_rtsp_lower_trans_get_type (void)
|
||||||
static void gst_rtspsrc_base_init (gpointer g_class);
|
static void gst_rtspsrc_base_init (gpointer g_class);
|
||||||
static void gst_rtspsrc_finalize (GObject * object);
|
static void gst_rtspsrc_finalize (GObject * object);
|
||||||
|
|
||||||
|
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_uri_handler_init (gpointer g_iface,
|
static void gst_rtspsrc_uri_handler_init (gpointer g_iface,
|
||||||
gpointer iface_data);
|
gpointer iface_data);
|
||||||
static GstCaps *gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media);
|
static GstCaps *gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media);
|
||||||
|
@ -173,11 +177,6 @@ static GstStateChangeReturn gst_rtspsrc_change_state (GstElement * element,
|
||||||
GstStateChange transition);
|
GstStateChange transition);
|
||||||
static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
|
static void gst_rtspsrc_handle_message (GstBin * bin, GstMessage * message);
|
||||||
|
|
||||||
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 gboolean gst_rtspsrc_open (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_open (GstRTSPSrc * src);
|
||||||
static gboolean gst_rtspsrc_play (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_play (GstRTSPSrc * src);
|
||||||
static gboolean gst_rtspsrc_pause (GstRTSPSrc * src);
|
static gboolean gst_rtspsrc_pause (GstRTSPSrc * src);
|
||||||
|
@ -186,6 +185,7 @@ static gboolean gst_rtspsrc_close (GstRTSPSrc * src);
|
||||||
static gboolean gst_rtspsrc_uri_set_uri (GstURIHandler * handler,
|
static gboolean gst_rtspsrc_uri_set_uri (GstURIHandler * handler,
|
||||||
const gchar * uri);
|
const gchar * uri);
|
||||||
|
|
||||||
|
static gboolean gst_rtspsrc_activate_streams (GstRTSPSrc * src);
|
||||||
static void gst_rtspsrc_loop (GstRTSPSrc * src);
|
static void gst_rtspsrc_loop (GstRTSPSrc * src);
|
||||||
|
|
||||||
/* commands we send to out loop to notify it of events */
|
/* commands we send to out loop to notify it of events */
|
||||||
|
@ -397,6 +397,7 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
|
||||||
/* we mark the pad as not linked, we will mark it as OK when we add the pad to
|
/* we mark the pad as not linked, we will mark it as OK when we add the pad to
|
||||||
* the element. */
|
* the element. */
|
||||||
stream->last_ret = GST_FLOW_NOT_LINKED;
|
stream->last_ret = GST_FLOW_NOT_LINKED;
|
||||||
|
stream->added = FALSE;
|
||||||
stream->id = src->numstreams++;
|
stream->id = src->numstreams++;
|
||||||
|
|
||||||
/* we must have a payload. No payload means we cannot create caps */
|
/* we must have a payload. No payload means we cannot create caps */
|
||||||
|
@ -448,21 +449,74 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
|
||||||
return stream;
|
return stream;
|
||||||
}
|
}
|
||||||
|
|
||||||
#if 0
|
|
||||||
static void
|
static void
|
||||||
gst_rtspsrc_free_stream (GstRTSPSrc * src, GstRTSPStream * stream)
|
gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
|
||||||
{
|
{
|
||||||
if (stream->caps) {
|
gint i;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "free stream %p", stream);
|
||||||
|
|
||||||
|
if (stream->caps)
|
||||||
gst_caps_unref (stream->caps);
|
gst_caps_unref (stream->caps);
|
||||||
}
|
|
||||||
g_free (stream->setup_url);
|
g_free (stream->setup_url);
|
||||||
|
|
||||||
src->streams = g_list_remove (src->streams, stream);
|
for (i = 0; i < 2; i++) {
|
||||||
src->numstreams--;
|
GstElement *udpsrc = stream->udpsrc[i];
|
||||||
|
|
||||||
|
if (udpsrc) {
|
||||||
|
GstPad *pad;
|
||||||
|
|
||||||
|
/* unlink the pad */
|
||||||
|
pad = gst_element_get_pad (udpsrc, "src");
|
||||||
|
if (stream->channelpad[i]) {
|
||||||
|
gst_pad_unlink (pad, stream->channelpad[i]);
|
||||||
|
gst_object_unref (stream->channelpad[i]);
|
||||||
|
stream->channelpad[i] = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
gst_element_set_state (udpsrc, GST_STATE_NULL);
|
||||||
|
gst_bin_remove (GST_BIN_CAST (src), udpsrc);
|
||||||
|
gst_object_unref (stream->udpsrc[i]);
|
||||||
|
stream->udpsrc[i] = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (stream->sess) {
|
||||||
|
gst_element_set_state (stream->sess, GST_STATE_NULL);
|
||||||
|
gst_bin_remove (GST_BIN_CAST (src), stream->sess);
|
||||||
|
stream->sess = NULL;
|
||||||
|
}
|
||||||
|
if (stream->srcpad) {
|
||||||
|
gst_pad_set_active (stream->srcpad, FALSE);
|
||||||
|
if (stream->added) {
|
||||||
|
gst_element_remove_pad (GST_ELEMENT_CAST (src), stream->srcpad);
|
||||||
|
stream->added = FALSE;
|
||||||
|
}
|
||||||
|
stream->srcpad = NULL;
|
||||||
|
}
|
||||||
g_free (stream);
|
g_free (stream);
|
||||||
}
|
}
|
||||||
#endif
|
|
||||||
|
static void
|
||||||
|
gst_rtspsrc_cleanup (GstRTSPSrc * src)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "cleanup");
|
||||||
|
|
||||||
|
for (walk = src->streams; walk; walk = g_list_next (walk)) {
|
||||||
|
GstRTSPStream *stream = (GstRTSPStream *) walk->data;
|
||||||
|
|
||||||
|
gst_rtspsrc_stream_free (src, stream);
|
||||||
|
}
|
||||||
|
g_list_free (src->streams);
|
||||||
|
src->streams = NULL;
|
||||||
|
src->numstreams = 0;
|
||||||
|
if (src->props)
|
||||||
|
gst_structure_free (src->props);
|
||||||
|
src->props = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define PARSE_INT(p, del, res) \
|
#define PARSE_INT(p, del, res) \
|
||||||
G_STMT_START { \
|
G_STMT_START { \
|
||||||
|
@ -724,8 +778,12 @@ again:
|
||||||
|
|
||||||
/* we keep these elements, we configure all in configure_transport when the
|
/* we keep these elements, we configure all in configure_transport when the
|
||||||
* server told us to really use the UDP ports. */
|
* server told us to really use the UDP ports. */
|
||||||
stream->udpsrc[0] = udpsrc0;
|
stream->udpsrc[0] = gst_object_ref (udpsrc0);
|
||||||
stream->udpsrc[1] = udpsrc1;
|
stream->udpsrc[1] = gst_object_ref (udpsrc1);
|
||||||
|
|
||||||
|
/* they are ours now */
|
||||||
|
gst_object_sink (udpsrc0);
|
||||||
|
gst_object_sink (udpsrc1);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
|
@ -780,6 +838,44 @@ cleanup:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pad_unblocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
pad_blocked (GstPad * pad, gboolean blocked, GstRTSPSrc * src)
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "pad %s:%s blocked, activating streams",
|
||||||
|
GST_DEBUG_PAD_NAME (pad));
|
||||||
|
|
||||||
|
gst_pad_set_blocked_async (pad, FALSE, (GstPadBlockCallback) pad_unblocked,
|
||||||
|
src);
|
||||||
|
|
||||||
|
/* activate the streams */
|
||||||
|
GST_OBJECT_LOCK (src);
|
||||||
|
if (!src->need_activate)
|
||||||
|
goto was_ok;
|
||||||
|
|
||||||
|
src->need_activate = FALSE;
|
||||||
|
GST_OBJECT_UNLOCK (src);
|
||||||
|
|
||||||
|
gst_rtspsrc_activate_streams (src);
|
||||||
|
|
||||||
|
return;
|
||||||
|
|
||||||
|
was_ok:
|
||||||
|
{
|
||||||
|
GST_OBJECT_UNLOCK (src);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* sets up all elements needed for streaming over the specified transport.
|
||||||
|
* Does not yet expose the element pads, this will be done when there is actuall
|
||||||
|
* dataflow detected, which might never happen when UDP is blocked in a
|
||||||
|
* firewall, for example.
|
||||||
|
*/
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
RTSPTransport * transport)
|
RTSPTransport * transport)
|
||||||
|
@ -799,15 +895,17 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
|
|
||||||
s = gst_caps_get_structure (stream->caps, 0);
|
s = gst_caps_get_structure (stream->caps, 0);
|
||||||
|
|
||||||
|
/* get the proper mime type for this stream now */
|
||||||
if ((res = rtsp_transport_get_mime (transport->trans, &mime)) < 0)
|
if ((res = rtsp_transport_get_mime (transport->trans, &mime)) < 0)
|
||||||
goto no_mime;
|
goto no_mime;
|
||||||
if (!mime)
|
if (!mime)
|
||||||
goto no_mime;
|
goto no_mime;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "setting mime to %s", mime);
|
|
||||||
/* configure the final mime type */
|
/* configure the final mime type */
|
||||||
|
GST_DEBUG_OBJECT (src, "setting mime to %s", mime);
|
||||||
gst_structure_set_name (s, mime);
|
gst_structure_set_name (s, mime);
|
||||||
|
|
||||||
|
/* find a manager */
|
||||||
if ((res = rtsp_transport_get_manager (transport->trans, &manager)) < 0)
|
if ((res = rtsp_transport_get_manager (transport->trans, &manager)) < 0)
|
||||||
goto no_manager;
|
goto no_manager;
|
||||||
|
|
||||||
|
@ -824,6 +922,8 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
if (ret != GST_STATE_CHANGE_SUCCESS)
|
if (ret != GST_STATE_CHANGE_SUCCESS)
|
||||||
goto start_session_failure;
|
goto start_session_failure;
|
||||||
|
|
||||||
|
/* we stream directly to the manager, FIXME, pad names should not be
|
||||||
|
* hardcoded. */
|
||||||
stream->channelpad[0] = gst_element_get_pad (stream->sess, "sinkrtp");
|
stream->channelpad[0] = gst_element_get_pad (stream->sess, "sinkrtp");
|
||||||
stream->channelpad[1] = gst_element_get_pad (stream->sess, "sinkrtcp");
|
stream->channelpad[1] = gst_element_get_pad (stream->sess, "sinkrtcp");
|
||||||
}
|
}
|
||||||
|
@ -847,22 +947,24 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
stream->udpsrc[i] = NULL;
|
stream->udpsrc[i] = NULL;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* no session manager, send data to srcpad directly */
|
/* no session manager, send data to srcpad directly */
|
||||||
if (!stream->channelpad[0]) {
|
if (!stream->channelpad[0]) {
|
||||||
GST_DEBUG_OBJECT (src, "no manager, creating pad");
|
GST_DEBUG_OBJECT (src, "no manager, creating pad");
|
||||||
|
|
||||||
|
/* create a new pad we will use to stream to */
|
||||||
name = g_strdup_printf ("stream%d", stream->id);
|
name = g_strdup_printf ("stream%d", stream->id);
|
||||||
template = gst_static_pad_template_get (&rtptemplate);
|
template = gst_static_pad_template_get (&rtptemplate);
|
||||||
stream->srcpad = gst_pad_new_from_template (template, name);
|
stream->channelpad[0] = gst_pad_new_from_template (template, name);
|
||||||
gst_object_unref (template);
|
gst_object_unref (template);
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
gst_pad_use_fixed_caps (stream->srcpad);
|
/* set caps and activate */
|
||||||
gst_pad_set_caps (stream->srcpad, stream->caps);
|
gst_pad_use_fixed_caps (stream->channelpad[0]);
|
||||||
|
gst_pad_set_caps (stream->channelpad[0], stream->caps);
|
||||||
|
gst_pad_set_active (stream->channelpad[0], TRUE);
|
||||||
|
|
||||||
stream->channelpad[0] = gst_object_ref (stream->srcpad);
|
outpad = gst_object_ref (stream->channelpad[0]);
|
||||||
gst_pad_set_active (stream->srcpad, TRUE);
|
|
||||||
gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
|
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (src, "using manager source pad");
|
GST_DEBUG_OBJECT (src, "using manager source pad");
|
||||||
outpad = gst_element_get_pad (stream->sess, "srcrtp");
|
outpad = gst_element_get_pad (stream->sess, "srcrtp");
|
||||||
|
@ -884,6 +986,10 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
if (stream->udpsrc[0] == NULL)
|
if (stream->udpsrc[0] == NULL)
|
||||||
goto no_element;
|
goto no_element;
|
||||||
|
|
||||||
|
/* take ownership */
|
||||||
|
gst_object_ref (stream->udpsrc[0]);
|
||||||
|
gst_object_sink (stream->udpsrc[0]);
|
||||||
|
|
||||||
/* change state */
|
/* change state */
|
||||||
gst_element_set_state (stream->udpsrc[0], GST_STATE_PAUSED);
|
gst_element_set_state (stream->udpsrc[0], GST_STATE_PAUSED);
|
||||||
}
|
}
|
||||||
|
@ -897,6 +1003,10 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
if (stream->udpsrc[1] == NULL)
|
if (stream->udpsrc[1] == NULL)
|
||||||
goto no_element;
|
goto no_element;
|
||||||
|
|
||||||
|
/* take ownership */
|
||||||
|
gst_object_ref (stream->udpsrc[0]);
|
||||||
|
gst_object_sink (stream->udpsrc[0]);
|
||||||
|
|
||||||
gst_element_set_state (stream->udpsrc[1], GST_STATE_PAUSED);
|
gst_element_set_state (stream->udpsrc[1], GST_STATE_PAUSED);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -904,8 +1014,6 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
/* we manage the UDP elements now. For unicast, the UDP sources where
|
/* we manage the UDP elements now. For unicast, the UDP sources where
|
||||||
* allocated in the stream when we suggested a transport. */
|
* allocated in the stream when we suggested a transport. */
|
||||||
if (stream->udpsrc[0]) {
|
if (stream->udpsrc[0]) {
|
||||||
GstPad *pad;
|
|
||||||
|
|
||||||
gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]);
|
gst_bin_add (GST_BIN_CAST (src), stream->udpsrc[0]);
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "setting up UDP source");
|
GST_DEBUG_OBJECT (src, "setting up UDP source");
|
||||||
|
@ -913,22 +1021,31 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
/* set caps */
|
/* set caps */
|
||||||
g_object_set (G_OBJECT (stream->udpsrc[0]), "caps", stream->caps, NULL);
|
g_object_set (G_OBJECT (stream->udpsrc[0]), "caps", stream->caps, NULL);
|
||||||
|
|
||||||
/* configure a timeout on the UDP port */
|
/* configure a timeout on the UDP port. When the timeout message is
|
||||||
|
* posted, we assume UDP transport is not possible. We reconnect using TCP
|
||||||
|
* if we can. */
|
||||||
g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->timeout,
|
g_object_set (G_OBJECT (stream->udpsrc[0]), "timeout", src->timeout,
|
||||||
NULL);
|
NULL);
|
||||||
|
|
||||||
|
/* get output pad of the UDP source. */
|
||||||
|
outpad = gst_element_get_pad (stream->udpsrc[0], "src");
|
||||||
|
|
||||||
|
/* configure pad block on the pad. As soon as there is dataflow on the
|
||||||
|
* UDP source, we know that UDP is not blocked by a firewall and we can
|
||||||
|
* configure all the streams to let the application autoplug decoders. */
|
||||||
|
gst_pad_set_blocked_async (outpad, TRUE,
|
||||||
|
(GstPadBlockCallback) pad_blocked, src);
|
||||||
|
|
||||||
if (stream->channelpad[0]) {
|
if (stream->channelpad[0]) {
|
||||||
GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager");
|
GST_DEBUG_OBJECT (src, "connecting UDP source 0 to manager");
|
||||||
/* configure for UDP delivery, we need to connect the UDP pads to
|
/* configure for UDP delivery, we need to connect the UDP pads to
|
||||||
* the session plugin. */
|
* the session plugin. */
|
||||||
pad = gst_element_get_pad (stream->udpsrc[0], "src");
|
gst_pad_link (outpad, stream->channelpad[0]);
|
||||||
gst_pad_link (pad, stream->channelpad[0]);
|
gst_object_unref (outpad);
|
||||||
gst_object_unref (pad);
|
/* the real output pad is that of the session manager */
|
||||||
|
|
||||||
outpad = gst_element_get_pad (stream->sess, "srcrtp");
|
outpad = gst_element_get_pad (stream->sess, "srcrtp");
|
||||||
} else {
|
} else {
|
||||||
GST_DEBUG_OBJECT (src, "using UDP src pad as output");
|
GST_DEBUG_OBJECT (src, "using UDP src pad as output");
|
||||||
outpad = gst_element_get_pad (stream->udpsrc[0], "src");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -947,13 +1064,14 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (outpad && !stream->srcpad) {
|
if (outpad) {
|
||||||
GST_DEBUG_OBJECT (src, "creating ghostpad");
|
GST_DEBUG_OBJECT (src, "creating ghostpad");
|
||||||
|
|
||||||
gst_pad_use_fixed_caps (outpad);
|
gst_pad_use_fixed_caps (outpad);
|
||||||
gst_pad_set_caps (outpad, stream->caps);
|
gst_pad_set_caps (outpad, stream->caps);
|
||||||
|
|
||||||
/* create ghostpad */
|
/* create ghostpad, don't add just yet, this will be done when we activate
|
||||||
|
* the stream. */
|
||||||
name = g_strdup_printf ("stream%d", stream->id);
|
name = g_strdup_printf ("stream%d", stream->id);
|
||||||
template = gst_static_pad_template_get (&rtptemplate);
|
template = gst_static_pad_template_get (&rtptemplate);
|
||||||
stream->srcpad = gst_ghost_pad_new_from_template (name, outpad, template);
|
stream->srcpad = gst_ghost_pad_new_from_template (name, outpad, template);
|
||||||
|
@ -961,10 +1079,6 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
||||||
g_free (name);
|
g_free (name);
|
||||||
|
|
||||||
gst_object_unref (outpad);
|
gst_object_unref (outpad);
|
||||||
|
|
||||||
/* and add */
|
|
||||||
gst_pad_set_active (stream->srcpad, TRUE);
|
|
||||||
gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
|
|
||||||
}
|
}
|
||||||
/* mark pad as ok */
|
/* mark pad as ok */
|
||||||
stream->last_ret = GST_FLOW_OK;
|
stream->last_ret = GST_FLOW_OK;
|
||||||
|
@ -994,6 +1108,35 @@ start_session_failure:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Adds the source pads of all configured streams to the element.
|
||||||
|
* This code is performed when we detected dataflow.
|
||||||
|
*
|
||||||
|
* We detect dataflow from either the _loop function or with pad probes on the
|
||||||
|
* udp sources.
|
||||||
|
*/
|
||||||
|
static gboolean
|
||||||
|
gst_rtspsrc_activate_streams (GstRTSPSrc * src)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
|
||||||
|
for (walk = src->streams; walk; walk = g_list_next (walk)) {
|
||||||
|
GstRTSPStream *stream = (GstRTSPStream *) walk->data;
|
||||||
|
|
||||||
|
gst_pad_set_active (stream->srcpad, TRUE);
|
||||||
|
/* add the pad */
|
||||||
|
if (!stream->added) {
|
||||||
|
gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
|
||||||
|
stream->added = TRUE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* if we got here all was configured. We have dynamic pads so we notify that
|
||||||
|
* we are done */
|
||||||
|
gst_element_no_more_pads (GST_ELEMENT_CAST (src));
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
|
||||||
static gint
|
static gint
|
||||||
find_stream_by_channel (GstRTSPStream * stream, gconstpointer a)
|
find_stream_by_channel (GstRTSPStream * stream, gconstpointer a)
|
||||||
{
|
{
|
||||||
|
@ -1144,6 +1287,11 @@ gst_rtspsrc_loop_interleaved (GstRTSPSrc * src)
|
||||||
GST_DEBUG_OBJECT (src, "pushing data of size %d on channel %d", size,
|
GST_DEBUG_OBJECT (src, "pushing data of size %d on channel %d", size,
|
||||||
channel);
|
channel);
|
||||||
|
|
||||||
|
if (src->need_activate) {
|
||||||
|
gst_rtspsrc_activate_streams (src);
|
||||||
|
src->need_activate = FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
/* chain to the peer pad */
|
/* chain to the peer pad */
|
||||||
if (GST_PAD_IS_SINK (outpad))
|
if (GST_PAD_IS_SINK (outpad))
|
||||||
ret = gst_pad_chain (outpad, buf);
|
ret = gst_pad_chain (outpad, buf);
|
||||||
|
@ -1239,21 +1387,9 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
|
||||||
}
|
}
|
||||||
GST_OBJECT_UNLOCK (src);
|
GST_OBJECT_UNLOCK (src);
|
||||||
|
|
||||||
if (restart) {
|
/* no need to restart, we're done */
|
||||||
gst_rtspsrc_pause (src);
|
if (!restart)
|
||||||
|
goto done;
|
||||||
if (src->task) {
|
|
||||||
/* stop task, we cannot join as this would deadlock */
|
|
||||||
gst_task_stop (src->task);
|
|
||||||
/* and free the task so that _close will not stop/join it again. */
|
|
||||||
gst_object_unref (GST_OBJECT (src->task));
|
|
||||||
src->task = NULL;
|
|
||||||
}
|
|
||||||
gst_rtspsrc_close (src);
|
|
||||||
|
|
||||||
/* see if we have TCP left to try */
|
|
||||||
if (src->cur_protocols & RTSP_LOWER_TRANS_TCP) {
|
|
||||||
gchar *url, *pos;
|
|
||||||
|
|
||||||
/* We post a warning message now to inform the user
|
/* We post a warning message now to inform the user
|
||||||
* that nothing happened. It's most likely a firewall thing. */
|
* that nothing happened. It's most likely a firewall thing. */
|
||||||
|
@ -1264,24 +1400,32 @@ gst_rtspsrc_loop_udp (GstRTSPSrc * src)
|
||||||
/* we can try only TCP now */
|
/* we can try only TCP now */
|
||||||
src->cur_protocols = RTSP_LOWER_TRANS_TCP;
|
src->cur_protocols = RTSP_LOWER_TRANS_TCP;
|
||||||
|
|
||||||
pos = strstr (src->location, "://");
|
/* pause to prepare for a restart */
|
||||||
if (!pos)
|
gst_rtspsrc_pause (src);
|
||||||
goto weird_url;
|
|
||||||
|
|
||||||
url = g_strdup_printf ("rtspt://%s", pos + 3);
|
if (src->task) {
|
||||||
|
/* stop task, we cannot join as this would deadlock */
|
||||||
|
gst_task_stop (src->task);
|
||||||
|
/* and free the task so that _close will not stop/join it again. */
|
||||||
|
gst_object_unref (GST_OBJECT (src->task));
|
||||||
|
src->task = NULL;
|
||||||
|
}
|
||||||
|
/* close and cleanup our state */
|
||||||
|
gst_rtspsrc_close (src);
|
||||||
|
|
||||||
gst_element_post_message (GST_ELEMENT_CAST (src),
|
/* see if we have TCP left to try */
|
||||||
gst_message_new_element (GST_OBJECT_CAST (src),
|
if (!(src->cur_protocols & RTSP_LOWER_TRANS_TCP))
|
||||||
gst_structure_new ("redirect",
|
goto no_protocols;
|
||||||
"new-location", G_TYPE_STRING, url, NULL)));
|
|
||||||
g_free (url);
|
/* open new connection using tcp */
|
||||||
} else {
|
if (!gst_rtspsrc_open (src))
|
||||||
src->cur_protocols = 0;
|
goto open_failed;
|
||||||
/* no transport possible, post an error and stop */
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
/* start playback */
|
||||||
("Could not connect to server, no protocols left"));
|
if (!gst_rtspsrc_play (src))
|
||||||
}
|
goto play_failed;
|
||||||
}
|
|
||||||
|
done:
|
||||||
return;
|
return;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
@ -1292,10 +1436,22 @@ stopping:
|
||||||
gst_task_pause (src->task);
|
gst_task_pause (src->task);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
weird_url:
|
no_protocols:
|
||||||
{
|
{
|
||||||
|
src->cur_protocols = 0;
|
||||||
|
/* no transport possible, post an error and stop */
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
GST_ELEMENT_ERROR (src, RESOURCE, READ, (NULL),
|
||||||
("Could not redirect, location %s is invalid", src->location));
|
("Could not connect to server, no protocols left"));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
open_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "open failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
play_failed:
|
||||||
|
{
|
||||||
|
GST_DEBUG_OBJECT (src, "play failed");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1414,10 +1570,8 @@ next:
|
||||||
|
|
||||||
/* store new content base if any */
|
/* store new content base if any */
|
||||||
rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base);
|
rtsp_message_get_header (response, RTSP_HDR_CONTENT_BASE, &content_base);
|
||||||
if (content_base) {
|
|
||||||
g_free (src->content_base);
|
g_free (src->content_base);
|
||||||
src->content_base = g_strdup (content_base);
|
src->content_base = g_strdup (content_base);
|
||||||
}
|
|
||||||
|
|
||||||
if (src->extension && src->extension->after_send)
|
if (src->extension && src->extension->after_send)
|
||||||
src->extension->after_send (src->extension, request, response);
|
src->extension->after_send (src->extension, request, response);
|
||||||
|
@ -1509,7 +1663,7 @@ gst_rtspsrc_parse_methods (GstRTSPSrc * src, RTSPMessage * response)
|
||||||
method = rtsp_find_method (stripped);
|
method = rtsp_find_method (stripped);
|
||||||
|
|
||||||
/* keep bitfield of supported methods */
|
/* keep bitfield of supported methods */
|
||||||
if (method != -1)
|
if (method != RTSP_INVALID)
|
||||||
src->methods |= method;
|
src->methods |= method;
|
||||||
}
|
}
|
||||||
g_strfreev (options);
|
g_strfreev (options);
|
||||||
|
@ -1556,6 +1710,7 @@ gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
|
||||||
if (*transports != NULL)
|
if (*transports != NULL)
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
|
||||||
|
/* the default RTSP transports */
|
||||||
result = g_strdup ("");
|
result = g_strdup ("");
|
||||||
if (protocols & RTSP_LOWER_TRANS_UDP) {
|
if (protocols & RTSP_LOWER_TRANS_UDP) {
|
||||||
gchar *new;
|
gchar *new;
|
||||||
|
@ -1602,7 +1757,7 @@ failed:
|
||||||
}
|
}
|
||||||
|
|
||||||
static RTSPResult
|
static RTSPResult
|
||||||
gst_rtspsrc_configure_transports (GstRTSPStream * stream, gchar ** transports)
|
gst_rtspsrc_prepare_transports (GstRTSPStream * stream, gchar ** transports)
|
||||||
{
|
{
|
||||||
GstRTSPSrc *src;
|
GstRTSPSrc *src;
|
||||||
gint nr_udp, nr_int;
|
gint nr_udp, nr_int;
|
||||||
|
@ -1668,6 +1823,193 @@ failed:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static gboolean
|
||||||
|
gst_rtspsrc_setup_streams (GstRTSPSrc * src)
|
||||||
|
{
|
||||||
|
GList *walk;
|
||||||
|
RTSPResult res;
|
||||||
|
RTSPMessage request = { 0 };
|
||||||
|
RTSPMessage response = { 0 };
|
||||||
|
GstRTSPStream *stream = NULL;
|
||||||
|
RTSPLowerTrans protocols;
|
||||||
|
|
||||||
|
/* we initially allow all configured lower transports. based on the URL
|
||||||
|
* transports and the replies from the server we narrow them down. */
|
||||||
|
protocols = src->url->transports & src->cur_protocols;
|
||||||
|
|
||||||
|
/* reset some state */
|
||||||
|
src->free_channel = 0;
|
||||||
|
src->interleaved = FALSE;
|
||||||
|
|
||||||
|
for (walk = src->streams; walk; walk = g_list_next (walk)) {
|
||||||
|
gchar *transports;
|
||||||
|
|
||||||
|
stream = (GstRTSPStream *) walk->data;
|
||||||
|
|
||||||
|
/* see if we need to configure this stream */
|
||||||
|
if (src->extension && src->extension->configure_stream) {
|
||||||
|
if (!src->extension->configure_stream (src->extension, stream)) {
|
||||||
|
GST_DEBUG_OBJECT (src, "skipping stream %p, disabled by extension",
|
||||||
|
stream);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* merge/overwrite global caps */
|
||||||
|
if (stream->caps) {
|
||||||
|
guint j, num;
|
||||||
|
GstStructure *s;
|
||||||
|
|
||||||
|
s = gst_caps_get_structure (stream->caps, 0);
|
||||||
|
|
||||||
|
num = gst_structure_n_fields (src->props);
|
||||||
|
for (j = 0; j < num; j++) {
|
||||||
|
const gchar *name;
|
||||||
|
const GValue *val;
|
||||||
|
|
||||||
|
name = gst_structure_nth_field_name (src->props, j);
|
||||||
|
val = gst_structure_get_value (src->props, name);
|
||||||
|
gst_structure_set_value (s, name, val);
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "copied %s", name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* skip setup if we have no URL for it */
|
||||||
|
if (stream->setup_url == NULL) {
|
||||||
|
GST_DEBUG_OBJECT (src, "skipping stream %p, no setup", stream);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
GST_DEBUG_OBJECT (src, "doing setup of stream %p with %s", stream,
|
||||||
|
stream->setup_url);
|
||||||
|
|
||||||
|
/* create a string with all the transports */
|
||||||
|
res = gst_rtspsrc_create_transports_string (src, protocols, &transports);
|
||||||
|
if (res < 0)
|
||||||
|
goto setup_transport_failed;
|
||||||
|
|
||||||
|
/* replace placeholders with real values, this function will optionally
|
||||||
|
* allocate UDP ports and other info needed to execute the setup request */
|
||||||
|
res = gst_rtspsrc_prepare_transports (stream, &transports);
|
||||||
|
if (res < 0)
|
||||||
|
goto setup_transport_failed;
|
||||||
|
|
||||||
|
/* create SETUP request */
|
||||||
|
res = rtsp_message_init_request (&request, RTSP_SETUP, stream->setup_url);
|
||||||
|
if (res < 0)
|
||||||
|
goto create_request_failed;
|
||||||
|
|
||||||
|
/* select transport, copy is made when adding to header so we can free it. */
|
||||||
|
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
|
||||||
|
g_free (transports);
|
||||||
|
|
||||||
|
if (!gst_rtspsrc_send (src, &request, &response, NULL))
|
||||||
|
goto send_error;
|
||||||
|
|
||||||
|
/* parse response transport */
|
||||||
|
{
|
||||||
|
gchar *resptrans = NULL;
|
||||||
|
RTSPTransport transport = { 0 };
|
||||||
|
|
||||||
|
rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
|
||||||
|
if (!resptrans)
|
||||||
|
goto no_transport;
|
||||||
|
|
||||||
|
/* parse transport */
|
||||||
|
if (rtsp_transport_parse (resptrans, &transport) != RTSP_OK)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
/* update allowed transports for other streams. once the transport of
|
||||||
|
* one stream has been determined, we make sure that all other streams
|
||||||
|
* are configured in the same way */
|
||||||
|
switch (transport.lower_transport) {
|
||||||
|
case RTSP_LOWER_TRANS_TCP:
|
||||||
|
GST_DEBUG_OBJECT (src, "stream %p as TCP interleaved", stream);
|
||||||
|
protocols = RTSP_LOWER_TRANS_TCP;
|
||||||
|
src->interleaved = TRUE;
|
||||||
|
/* update free channels */
|
||||||
|
src->free_channel =
|
||||||
|
MAX (transport.interleaved.min, src->free_channel);
|
||||||
|
src->free_channel =
|
||||||
|
MAX (transport.interleaved.max, src->free_channel);
|
||||||
|
src->free_channel++;
|
||||||
|
break;
|
||||||
|
case RTSP_LOWER_TRANS_UDP_MCAST:
|
||||||
|
/* only allow multicast for other streams */
|
||||||
|
GST_DEBUG_OBJECT (src, "stream %p as UDP multicast", stream);
|
||||||
|
protocols = RTSP_LOWER_TRANS_UDP_MCAST;
|
||||||
|
break;
|
||||||
|
case RTSP_LOWER_TRANS_UDP:
|
||||||
|
/* only allow unicast for other streams */
|
||||||
|
GST_DEBUG_OBJECT (src, "stream %p as UDP unicast", stream);
|
||||||
|
protocols = RTSP_LOWER_TRANS_UDP;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
GST_DEBUG_OBJECT (src, "stream %p unknown transport %d", stream,
|
||||||
|
transport.lower_transport);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!stream->container || !src->interleaved) {
|
||||||
|
/* now configure the stream with the selected transport */
|
||||||
|
if (!gst_rtspsrc_stream_configure_transport (stream, &transport)) {
|
||||||
|
GST_DEBUG_OBJECT (src,
|
||||||
|
"could not configure stream %p transport, skipping stream",
|
||||||
|
stream);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/* clean up our transport struct */
|
||||||
|
rtsp_transport_init (&transport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (src->extension && src->extension->stream_select)
|
||||||
|
src->extension->stream_select (src->extension);
|
||||||
|
|
||||||
|
/* we need to activate the streams when we detect activity */
|
||||||
|
src->need_activate = TRUE;
|
||||||
|
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
/* ERRORS */
|
||||||
|
create_request_failed:
|
||||||
|
{
|
||||||
|
gchar *str = rtsp_strresult (res);
|
||||||
|
|
||||||
|
GST_ELEMENT_ERROR (src, LIBRARY, INIT, (NULL),
|
||||||
|
("Could not create request. (%s)", str));
|
||||||
|
g_free (str);
|
||||||
|
goto cleanup_error;
|
||||||
|
}
|
||||||
|
setup_transport_failed:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
|
("Could not setup transport."));
|
||||||
|
goto cleanup_error;
|
||||||
|
}
|
||||||
|
send_error:
|
||||||
|
{
|
||||||
|
gchar *str = rtsp_strresult (res);
|
||||||
|
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, WRITE, (NULL),
|
||||||
|
("Could not send message. (%s)", str));
|
||||||
|
g_free (str);
|
||||||
|
goto cleanup_error;
|
||||||
|
}
|
||||||
|
no_transport:
|
||||||
|
{
|
||||||
|
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
||||||
|
("Server did not select transport."));
|
||||||
|
goto cleanup_error;
|
||||||
|
}
|
||||||
|
cleanup_error:
|
||||||
|
{
|
||||||
|
rtsp_message_unset (&request);
|
||||||
|
rtsp_message_unset (&response);
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
static gboolean
|
static gboolean
|
||||||
gst_rtspsrc_open (GstRTSPSrc * src)
|
gst_rtspsrc_open (GstRTSPSrc * src)
|
||||||
{
|
{
|
||||||
|
@ -1678,13 +2020,10 @@ gst_rtspsrc_open (GstRTSPSrc * src)
|
||||||
guint size;
|
guint size;
|
||||||
gint i, n_streams;
|
gint i, n_streams;
|
||||||
SDPMessage sdp = { 0 };
|
SDPMessage sdp = { 0 };
|
||||||
RTSPLowerTrans protocols;
|
|
||||||
GstRTSPStream *stream = NULL;
|
GstRTSPStream *stream = NULL;
|
||||||
gchar *respcont = NULL;
|
gchar *respcont = NULL;
|
||||||
|
|
||||||
/* reset our state */
|
/* reset our state */
|
||||||
src->free_channel = 0;
|
|
||||||
src->interleaved = FALSE;
|
|
||||||
gst_segment_init (&src->segment, GST_FORMAT_TIME);
|
gst_segment_init (&src->segment, GST_FORMAT_TIME);
|
||||||
|
|
||||||
/* can't continue without a valid url */
|
/* can't continue without a valid url */
|
||||||
|
@ -1758,139 +2097,14 @@ gst_rtspsrc_open (GstRTSPSrc * src)
|
||||||
if (src->extension && src->extension->parse_sdp)
|
if (src->extension && src->extension->parse_sdp)
|
||||||
src->extension->parse_sdp (src->extension, &sdp);
|
src->extension->parse_sdp (src->extension, &sdp);
|
||||||
|
|
||||||
/* we initially allow all configured lower transports. based on the URL
|
/* create streams */
|
||||||
* transports and the replies from the server we narrow them down. */
|
|
||||||
protocols = src->url->transports & src->cur_protocols;
|
|
||||||
|
|
||||||
/* setup streams */
|
|
||||||
n_streams = sdp_message_medias_len (&sdp);
|
n_streams = sdp_message_medias_len (&sdp);
|
||||||
for (i = 0; i < n_streams; i++) {
|
for (i = 0; i < n_streams; i++) {
|
||||||
gchar *transports;
|
|
||||||
|
|
||||||
/* create stream from the media, can never return NULL */
|
|
||||||
stream = gst_rtspsrc_create_stream (src, &sdp, i);
|
stream = gst_rtspsrc_create_stream (src, &sdp, i);
|
||||||
|
|
||||||
/* see if we need to configure this stream */
|
|
||||||
if (src->extension && src->extension->configure_stream) {
|
|
||||||
if (!src->extension->configure_stream (src->extension, stream)) {
|
|
||||||
GST_DEBUG_OBJECT (src, "skipping stream %d, disabled by extension", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* merge/overwrite global caps */
|
/* setup streams */
|
||||||
if (stream->caps) {
|
gst_rtspsrc_setup_streams (src);
|
||||||
guint j, num;
|
|
||||||
GstStructure *s;
|
|
||||||
|
|
||||||
s = gst_caps_get_structure (stream->caps, 0);
|
|
||||||
|
|
||||||
num = gst_structure_n_fields (src->props);
|
|
||||||
for (j = 0; j < num; j++) {
|
|
||||||
const gchar *name;
|
|
||||||
const GValue *val;
|
|
||||||
|
|
||||||
name = gst_structure_nth_field_name (src->props, j);
|
|
||||||
val = gst_structure_get_value (src->props, name);
|
|
||||||
gst_structure_set_value (s, name, val);
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "copied %s", name);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* skip setup if we have no URL for it */
|
|
||||||
if (stream->setup_url == NULL) {
|
|
||||||
GST_DEBUG_OBJECT (src, "skipping stream %d, no setup", i);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "doing setup of stream %d with %s", i,
|
|
||||||
stream->setup_url);
|
|
||||||
|
|
||||||
/* create SETUP request */
|
|
||||||
res = rtsp_message_init_request (&request, RTSP_SETUP, stream->setup_url);
|
|
||||||
if (res < 0)
|
|
||||||
goto create_request_failed;
|
|
||||||
|
|
||||||
/* create a string with all the transports */
|
|
||||||
res = gst_rtspsrc_create_transports_string (src, protocols, &transports);
|
|
||||||
if (res < 0)
|
|
||||||
goto setup_transport_failed;
|
|
||||||
|
|
||||||
/* replace placeholders with real values */
|
|
||||||
res = gst_rtspsrc_configure_transports (stream, &transports);
|
|
||||||
if (res < 0)
|
|
||||||
goto setup_transport_failed;
|
|
||||||
|
|
||||||
/* select transport, copy is made when adding to header */
|
|
||||||
rtsp_message_add_header (&request, RTSP_HDR_TRANSPORT, transports);
|
|
||||||
g_free (transports);
|
|
||||||
|
|
||||||
if (!gst_rtspsrc_send (src, &request, &response, NULL))
|
|
||||||
goto send_error;
|
|
||||||
|
|
||||||
/* parse response transport */
|
|
||||||
{
|
|
||||||
gchar *resptrans = NULL;
|
|
||||||
RTSPTransport transport = { 0 };
|
|
||||||
|
|
||||||
rtsp_message_get_header (&response, RTSP_HDR_TRANSPORT, &resptrans);
|
|
||||||
if (!resptrans)
|
|
||||||
goto no_transport;
|
|
||||||
|
|
||||||
/* parse transport */
|
|
||||||
if (rtsp_transport_parse (resptrans, &transport) != RTSP_OK)
|
|
||||||
continue;
|
|
||||||
|
|
||||||
/* update allowed transports for other streams. once the transport of
|
|
||||||
* one stream has been determined, we make sure that all other streams
|
|
||||||
* are configured in the same way */
|
|
||||||
switch (transport.lower_transport) {
|
|
||||||
case RTSP_LOWER_TRANS_TCP:
|
|
||||||
GST_DEBUG_OBJECT (src, "stream %d as TCP interleaved", i);
|
|
||||||
protocols = RTSP_LOWER_TRANS_TCP;
|
|
||||||
src->interleaved = TRUE;
|
|
||||||
/* update free channels */
|
|
||||||
src->free_channel =
|
|
||||||
MAX (transport.interleaved.min, src->free_channel);
|
|
||||||
src->free_channel =
|
|
||||||
MAX (transport.interleaved.max, src->free_channel);
|
|
||||||
src->free_channel++;
|
|
||||||
break;
|
|
||||||
case RTSP_LOWER_TRANS_UDP_MCAST:
|
|
||||||
/* only allow multicast for other streams */
|
|
||||||
GST_DEBUG_OBJECT (src, "stream %d as UDP multicast", i);
|
|
||||||
protocols = RTSP_LOWER_TRANS_UDP_MCAST;
|
|
||||||
break;
|
|
||||||
case RTSP_LOWER_TRANS_UDP:
|
|
||||||
/* only allow unicast for other streams */
|
|
||||||
GST_DEBUG_OBJECT (src, "stream %d as UDP unicast", i);
|
|
||||||
protocols = RTSP_LOWER_TRANS_UDP;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
GST_DEBUG_OBJECT (src, "stream %d unknown transport %d", i,
|
|
||||||
transport.lower_transport);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!stream->container || !src->interleaved) {
|
|
||||||
/* now configure the stream with the transport */
|
|
||||||
if (!gst_rtspsrc_stream_configure_transport (stream, &transport)) {
|
|
||||||
GST_DEBUG_OBJECT (src,
|
|
||||||
"could not configure stream %d transport, skipping stream", i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/* clean up our transport struct */
|
|
||||||
rtsp_transport_init (&transport);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (src->extension && src->extension->stream_select)
|
|
||||||
src->extension->stream_select (src->extension);
|
|
||||||
|
|
||||||
/* if we got here all was configured. We have dynamic pads so we notify that
|
|
||||||
* we are done */
|
|
||||||
gst_element_no_more_pads (GST_ELEMENT_CAST (src));
|
|
||||||
|
|
||||||
/* clean up any messages */
|
/* clean up any messages */
|
||||||
rtsp_message_unset (&request);
|
rtsp_message_unset (&request);
|
||||||
|
@ -1952,18 +2166,6 @@ wrong_content_type:
|
||||||
("Server does not support SDP, got %s.", respcont));
|
("Server does not support SDP, got %s.", respcont));
|
||||||
goto cleanup_error;
|
goto cleanup_error;
|
||||||
}
|
}
|
||||||
setup_transport_failed:
|
|
||||||
{
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
|
||||||
("Could not setup transport."));
|
|
||||||
goto cleanup_error;
|
|
||||||
}
|
|
||||||
no_transport:
|
|
||||||
{
|
|
||||||
GST_ELEMENT_ERROR (src, RESOURCE, SETTINGS, (NULL),
|
|
||||||
("Server did not select transport."));
|
|
||||||
goto cleanup_error;
|
|
||||||
}
|
|
||||||
cleanup_error:
|
cleanup_error:
|
||||||
{
|
{
|
||||||
rtsp_message_unset (&request);
|
rtsp_message_unset (&request);
|
||||||
|
@ -2018,6 +2220,13 @@ gst_rtspsrc_close (GstRTSPSrc * src)
|
||||||
if ((res = rtsp_connection_close (src->connection)) < 0)
|
if ((res = rtsp_connection_close (src->connection)) < 0)
|
||||||
goto close_failed;
|
goto close_failed;
|
||||||
|
|
||||||
|
/* free connection */
|
||||||
|
rtsp_connection_free (src->connection);
|
||||||
|
src->connection = NULL;
|
||||||
|
|
||||||
|
/* cleanup */
|
||||||
|
gst_rtspsrc_cleanup (src);
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
|
||||||
/* ERRORS */
|
/* ERRORS */
|
||||||
|
|
|
@ -78,11 +78,12 @@ typedef struct _GstRTSPStream GstRTSPStream;
|
||||||
struct _GstRTSPStream {
|
struct _GstRTSPStream {
|
||||||
gint id;
|
gint id;
|
||||||
|
|
||||||
GstRTSPSrc *parent;
|
GstRTSPSrc *parent; /* parent, no extra ref to parent is taken */
|
||||||
|
|
||||||
/* pad we expose or NULL when it does not have an actual pad */
|
/* pad we expose or NULL when it does not have an actual pad */
|
||||||
GstPad *srcpad;
|
GstPad *srcpad;
|
||||||
GstFlowReturn last_ret;
|
GstFlowReturn last_ret;
|
||||||
|
gboolean added;
|
||||||
|
|
||||||
/* for interleaved mode */
|
/* for interleaved mode */
|
||||||
gint channel[2];
|
gint channel[2];
|
||||||
|
@ -124,6 +125,7 @@ struct _GstRTSPSrc {
|
||||||
gint numstreams;
|
gint numstreams;
|
||||||
GList *streams;
|
GList *streams;
|
||||||
GstStructure *props;
|
GstStructure *props;
|
||||||
|
gboolean need_activate;
|
||||||
|
|
||||||
/* properties */
|
/* properties */
|
||||||
gchar *location;
|
gchar *location;
|
||||||
|
@ -141,8 +143,6 @@ struct _GstRTSPSrc {
|
||||||
gint methods;
|
gint methods;
|
||||||
|
|
||||||
RTSPConnection *connection;
|
RTSPConnection *connection;
|
||||||
RTSPMessage *request;
|
|
||||||
RTSPMessage *response;
|
|
||||||
|
|
||||||
RTSPExtensionCtx *extension;
|
RTSPExtensionCtx *extension;
|
||||||
};
|
};
|
||||||
|
|
|
@ -119,7 +119,6 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn)
|
||||||
gint ret;
|
gint ret;
|
||||||
RTSPConnection *newconn;
|
RTSPConnection *newconn;
|
||||||
|
|
||||||
g_return_val_if_fail (url != NULL, RTSP_EINVAL);
|
|
||||||
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
newconn = g_new (RTSPConnection, 1);
|
newconn = g_new (RTSPConnection, 1);
|
||||||
|
@ -139,6 +138,7 @@ rtsp_connection_create (RTSPUrl * url, RTSPConnection ** conn)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
newconn->url = url;
|
newconn->url = url;
|
||||||
|
newconn->fd = -1;
|
||||||
newconn->cseq = 0;
|
newconn->cseq = 0;
|
||||||
newconn->session_id[0] = 0;
|
newconn->session_id[0] = 0;
|
||||||
newconn->state = RTSP_STATE_INIT;
|
newconn->state = RTSP_STATE_INIT;
|
||||||
|
@ -169,6 +169,8 @@ rtsp_connection_connect (RTSPConnection * conn)
|
||||||
RTSPUrl *url;
|
RTSPUrl *url;
|
||||||
|
|
||||||
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
||||||
|
g_return_val_if_fail (conn->url != NULL, RTSP_EINVAL);
|
||||||
|
g_return_val_if_fail (conn->fd < 0, RTSP_EINVAL);
|
||||||
|
|
||||||
url = conn->url;
|
url = conn->url;
|
||||||
|
|
||||||
|
@ -252,11 +254,23 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
||||||
|
|
||||||
str = g_string_new ("");
|
str = g_string_new ("");
|
||||||
|
|
||||||
|
switch (message->type) {
|
||||||
|
case RTSP_MESSAGE_REQUEST:
|
||||||
/* create request string, add CSeq */
|
/* create request string, add CSeq */
|
||||||
g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
|
g_string_append_printf (str, "%s %s RTSP/1.0\r\n"
|
||||||
"CSeq: %d\r\n",
|
"CSeq: %d\r\n",
|
||||||
rtsp_method_as_text (message->type_data.request.method),
|
rtsp_method_as_text (message->type_data.request.method),
|
||||||
message->type_data.request.uri, conn->cseq);
|
message->type_data.request.uri, conn->cseq++);
|
||||||
|
break;
|
||||||
|
case RTSP_MESSAGE_RESPONSE:
|
||||||
|
/* create response string */
|
||||||
|
g_string_append_printf (str, "RTSP/1.0 %d %s\r\n",
|
||||||
|
message->type_data.response.code, message->type_data.response.reason);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
/* append session id if we have one */
|
/* append session id if we have one */
|
||||||
if (conn->session_id[0] != '\0') {
|
if (conn->session_id[0] != '\0') {
|
||||||
|
@ -300,8 +314,6 @@ rtsp_connection_send (RTSPConnection * conn, RTSPMessage * message)
|
||||||
}
|
}
|
||||||
g_string_free (str, TRUE);
|
g_string_free (str, TRUE);
|
||||||
|
|
||||||
conn->cseq++;
|
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
|
@ -328,14 +340,16 @@ write_error:
|
||||||
static RTSPResult
|
static RTSPResult
|
||||||
read_line (gint fd, gchar * buffer, guint size)
|
read_line (gint fd, gchar * buffer, guint size)
|
||||||
{
|
{
|
||||||
gint idx;
|
guint idx;
|
||||||
gchar c;
|
gchar c;
|
||||||
gint r;
|
gint r;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
while (TRUE) {
|
while (TRUE) {
|
||||||
r = read (fd, &c, 1);
|
r = read (fd, &c, 1);
|
||||||
if (r < 1) {
|
if (r == 0) {
|
||||||
|
goto eof;
|
||||||
|
} else if (r < 0) {
|
||||||
if (errno != EAGAIN && errno != EINTR)
|
if (errno != EAGAIN && errno != EINTR)
|
||||||
goto read_error;
|
goto read_error;
|
||||||
} else {
|
} else {
|
||||||
|
@ -352,6 +366,10 @@ read_line (gint fd, gchar * buffer, guint size)
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
|
||||||
|
eof:
|
||||||
|
{
|
||||||
|
return RTSP_EEOF;
|
||||||
|
}
|
||||||
read_error:
|
read_error:
|
||||||
{
|
{
|
||||||
return RTSP_ESYS;
|
return RTSP_ESYS;
|
||||||
|
@ -435,7 +453,7 @@ parse_request_line (gchar * buffer, RTSPMessage * msg)
|
||||||
|
|
||||||
read_string (methodstr, sizeof (methodstr), &bptr);
|
read_string (methodstr, sizeof (methodstr), &bptr);
|
||||||
method = rtsp_find_method (methodstr);
|
method = rtsp_find_method (methodstr);
|
||||||
if (method == -1)
|
if (method == RTSP_INVALID)
|
||||||
goto wrong_method;
|
goto wrong_method;
|
||||||
|
|
||||||
read_string (urlstr, sizeof (urlstr), &bptr);
|
read_string (urlstr, sizeof (urlstr), &bptr);
|
||||||
|
@ -476,7 +494,7 @@ parse_line (gchar * buffer, RTSPMessage * msg)
|
||||||
bptr++;
|
bptr++;
|
||||||
|
|
||||||
field = rtsp_find_header_field (key);
|
field = rtsp_find_header_field (key);
|
||||||
if (field != -1) {
|
if (field != RTSP_HDR_INVALID) {
|
||||||
while (g_ascii_isspace (*bptr))
|
while (g_ascii_isspace (*bptr))
|
||||||
bptr++;
|
bptr++;
|
||||||
rtsp_message_add_header (msg, field, bptr);
|
rtsp_message_add_header (msg, field, bptr);
|
||||||
|
@ -737,6 +755,7 @@ rtsp_connection_close (RTSPConnection * conn)
|
||||||
gint res;
|
gint res;
|
||||||
|
|
||||||
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (conn != NULL, RTSP_EINVAL);
|
||||||
|
g_return_val_if_fail (conn->fd >= 0, RTSP_EINVAL);
|
||||||
|
|
||||||
res = CLOSE_SOCKET (conn->fd);
|
res = CLOSE_SOCKET (conn->fd);
|
||||||
#ifdef G_OS_WIN32
|
#ifdef G_OS_WIN32
|
||||||
|
|
|
@ -57,7 +57,7 @@ static const gchar *rtsp_results[] = {
|
||||||
"Out of memory",
|
"Out of memory",
|
||||||
"Cannot resolve host",
|
"Cannot resolve host",
|
||||||
"Function not implemented",
|
"Function not implemented",
|
||||||
"System error: '%s'",
|
"System error: %s",
|
||||||
"Parse error",
|
"Parse error",
|
||||||
"Error on WSAStartup",
|
"Error on WSAStartup",
|
||||||
"Windows sockets are not version 0x202",
|
"Windows sockets are not version 0x202",
|
||||||
|
@ -142,11 +142,14 @@ static const gchar *rtsp_headers[] = {
|
||||||
NULL
|
NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
#define DEF_STATUS(c,t)
|
#define DEF_STATUS(c, t) \
|
||||||
|
g_hash_table_insert (statuses, GUINT_TO_POINTER(c), t)
|
||||||
|
|
||||||
void
|
GHashTable *
|
||||||
rtsp_init_status (void)
|
rtsp_init_status (void)
|
||||||
{
|
{
|
||||||
|
GHashTable *statuses = g_hash_table_new (NULL, NULL);
|
||||||
|
|
||||||
DEF_STATUS (RTSP_STS_CONTINUE, "Continue");
|
DEF_STATUS (RTSP_STS_CONTINUE, "Continue");
|
||||||
DEF_STATUS (RTSP_STS_OK, "OK");
|
DEF_STATUS (RTSP_STS_OK, "OK");
|
||||||
DEF_STATUS (RTSP_STS_CREATED, "Created");
|
DEF_STATUS (RTSP_STS_CREATED, "Created");
|
||||||
|
@ -196,6 +199,8 @@ rtsp_init_status (void)
|
||||||
DEF_STATUS (RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
|
DEF_STATUS (RTSP_STS_RTSP_VERSION_NOT_SUPPORTED,
|
||||||
"RTSP Version not supported");
|
"RTSP Version not supported");
|
||||||
DEF_STATUS (RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
|
DEF_STATUS (RTSP_STS_OPTION_NOT_SUPPORTED, "Option not supported");
|
||||||
|
|
||||||
|
return statuses;
|
||||||
}
|
}
|
||||||
|
|
||||||
gchar *
|
gchar *
|
||||||
|
@ -229,7 +234,7 @@ rtsp_method_as_text (RTSPMethod method)
|
||||||
{
|
{
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
if (method == 0)
|
if (method == RTSP_INVALID)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
i = 0;
|
i = 0;
|
||||||
|
@ -243,19 +248,21 @@ rtsp_method_as_text (RTSPMethod method)
|
||||||
const gchar *
|
const gchar *
|
||||||
rtsp_header_as_text (RTSPHeaderField field)
|
rtsp_header_as_text (RTSPHeaderField field)
|
||||||
{
|
{
|
||||||
return rtsp_headers[field];
|
if (field == RTSP_HDR_INVALID)
|
||||||
|
return NULL;
|
||||||
|
else
|
||||||
|
return rtsp_headers[field - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const gchar *
|
const gchar *
|
||||||
rtsp_status_as_text (RTSPStatusCode code)
|
rtsp_status_as_text (RTSPStatusCode code)
|
||||||
{
|
{
|
||||||
return NULL;
|
static GHashTable *statuses;
|
||||||
}
|
|
||||||
|
|
||||||
const gchar *
|
if (G_UNLIKELY (statuses == NULL))
|
||||||
rtsp_status_to_string (RTSPStatusCode code)
|
statuses = rtsp_init_status ();
|
||||||
{
|
|
||||||
return NULL;
|
return g_hash_table_lookup (statuses, GUINT_TO_POINTER (code));
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPHeaderField
|
RTSPHeaderField
|
||||||
|
@ -265,10 +272,10 @@ rtsp_find_header_field (gchar * header)
|
||||||
|
|
||||||
for (idx = 0; rtsp_headers[idx]; idx++) {
|
for (idx = 0; rtsp_headers[idx]; idx++) {
|
||||||
if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) {
|
if (g_ascii_strcasecmp (rtsp_headers[idx], header) == 0) {
|
||||||
return idx;
|
return idx + 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return RTSP_HDR_INVALID;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPMethod
|
RTSPMethod
|
||||||
|
@ -281,5 +288,5 @@ rtsp_find_method (gchar * method)
|
||||||
return (1 << idx);
|
return (1 << idx);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return -1;
|
return RTSP_INVALID;
|
||||||
}
|
}
|
||||||
|
|
|
@ -100,6 +100,8 @@ typedef enum {
|
||||||
} RTSPMethod;
|
} RTSPMethod;
|
||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
|
RTSP_HDR_INVALID,
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* R = Request
|
* R = Request
|
||||||
* r = response
|
* r = response
|
||||||
|
@ -217,7 +219,6 @@ gchar* rtsp_strresult (RTSPResult result);
|
||||||
const gchar* rtsp_method_as_text (RTSPMethod method);
|
const gchar* rtsp_method_as_text (RTSPMethod method);
|
||||||
const gchar* rtsp_header_as_text (RTSPHeaderField field);
|
const gchar* rtsp_header_as_text (RTSPHeaderField field);
|
||||||
const gchar* rtsp_status_as_text (RTSPStatusCode code);
|
const gchar* rtsp_status_as_text (RTSPStatusCode code);
|
||||||
const gchar* rtsp_status_to_string (RTSPStatusCode code);
|
|
||||||
|
|
||||||
RTSPHeaderField rtsp_find_header_field (gchar *header);
|
RTSPHeaderField rtsp_find_header_field (gchar *header);
|
||||||
RTSPMethod rtsp_find_method (gchar *method);
|
RTSPMethod rtsp_find_method (gchar *method);
|
||||||
|
|
|
@ -87,7 +87,7 @@ rtsp_ext_wms_after_send (RTSPExtensionCtx * ctx, RTSPMessage * req,
|
||||||
gchar *server = NULL;
|
gchar *server = NULL;
|
||||||
|
|
||||||
rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server);
|
rtsp_message_get_header (resp, RTSP_HDR_SERVER, &server);
|
||||||
if (g_str_has_prefix (server, SERVER_PREFIX))
|
if (server && g_str_has_prefix (server, SERVER_PREFIX))
|
||||||
rext->active = TRUE;
|
rext->active = TRUE;
|
||||||
else
|
else
|
||||||
rext->active = FALSE;
|
rext->active = FALSE;
|
||||||
|
@ -152,9 +152,13 @@ rtsp_ext_wms_configure_stream (RTSPExtensionCtx * ctx, GstRTSPStream * stream)
|
||||||
s = gst_caps_get_structure (stream->caps, 0);
|
s = gst_caps_get_structure (stream->caps, 0);
|
||||||
encoding = gst_structure_get_string (s, "encoding-name");
|
encoding = gst_structure_get_string (s, "encoding-name");
|
||||||
|
|
||||||
|
if (!encoding)
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
GST_DEBUG_OBJECT (src, "%" GST_PTR_FORMAT " encoding-name: %s", stream->caps,
|
GST_DEBUG_OBJECT (src, "%" GST_PTR_FORMAT " encoding-name: %s", stream->caps,
|
||||||
encoding);
|
encoding);
|
||||||
|
|
||||||
|
/* rtx streams do not need to be configured */
|
||||||
if (!strcmp (encoding, "x-wms-rtx"))
|
if (!strcmp (encoding, "x-wms-rtx"))
|
||||||
return FALSE;
|
return FALSE;
|
||||||
|
|
||||||
|
|
|
@ -41,10 +41,41 @@
|
||||||
* SOFTWARE.
|
* SOFTWARE.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
#include "rtspmessage.h"
|
#include "rtspmessage.h"
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_new_request (RTSPMessage ** msg, RTSPMethod method, gchar * uri)
|
rtsp_message_new (RTSPMessage ** msg)
|
||||||
|
{
|
||||||
|
RTSPMessage *newmsg;
|
||||||
|
|
||||||
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
|
newmsg = g_new0 (RTSPMessage, 1);
|
||||||
|
|
||||||
|
*msg = newmsg;
|
||||||
|
|
||||||
|
return rtsp_message_init (newmsg);
|
||||||
|
}
|
||||||
|
|
||||||
|
RTSPResult
|
||||||
|
rtsp_message_init (RTSPMessage * msg)
|
||||||
|
{
|
||||||
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
|
rtsp_message_unset (msg);
|
||||||
|
|
||||||
|
msg->type = RTSP_MESSAGE_INVALID;
|
||||||
|
msg->hdr_fields =
|
||||||
|
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
||||||
|
|
||||||
|
return RTSP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
RTSPResult
|
||||||
|
rtsp_message_new_request (RTSPMessage ** msg, RTSPMethod method,
|
||||||
|
const gchar * uri)
|
||||||
{
|
{
|
||||||
RTSPMessage *newmsg;
|
RTSPMessage *newmsg;
|
||||||
|
|
||||||
|
@ -59,10 +90,11 @@ rtsp_message_new_request (RTSPMessage ** msg, RTSPMethod method, gchar * uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method, gchar * uri)
|
rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method,
|
||||||
|
const gchar * uri)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (uri != NULL, RTSP_EINVAL);
|
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
|
g_return_val_if_fail (uri != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
rtsp_message_unset (msg);
|
rtsp_message_unset (msg);
|
||||||
|
|
||||||
|
@ -77,13 +109,11 @@ rtsp_message_init_request (RTSPMessage * msg, RTSPMethod method, gchar * uri)
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_new_response (RTSPMessage ** msg, RTSPStatusCode code,
|
rtsp_message_new_response (RTSPMessage ** msg, RTSPStatusCode code,
|
||||||
gchar * reason, RTSPMessage * request)
|
const gchar * reason, const RTSPMessage * request)
|
||||||
{
|
{
|
||||||
RTSPMessage *newmsg;
|
RTSPMessage *newmsg;
|
||||||
|
|
||||||
g_return_val_if_fail (reason != NULL, RTSP_EINVAL);
|
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (request != NULL, RTSP_EINVAL);
|
|
||||||
|
|
||||||
newmsg = g_new0 (RTSPMessage, 1);
|
newmsg = g_new0 (RTSPMessage, 1);
|
||||||
|
|
||||||
|
@ -94,13 +124,15 @@ rtsp_message_new_response (RTSPMessage ** msg, RTSPStatusCode code,
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
|
rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
|
||||||
gchar * reason, RTSPMessage * request)
|
const gchar * reason, const RTSPMessage * request)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (reason != NULL, RTSP_EINVAL);
|
|
||||||
|
|
||||||
rtsp_message_unset (msg);
|
rtsp_message_unset (msg);
|
||||||
|
|
||||||
|
if (reason == NULL)
|
||||||
|
reason = rtsp_status_as_text (code);
|
||||||
|
|
||||||
msg->type = RTSP_MESSAGE_RESPONSE;
|
msg->type = RTSP_MESSAGE_RESPONSE;
|
||||||
msg->type_data.response.code = code;
|
msg->type_data.response.code = code;
|
||||||
msg->type_data.response.reason = g_strdup (reason);
|
msg->type_data.response.reason = g_strdup (reason);
|
||||||
|
@ -108,7 +140,25 @@ rtsp_message_init_response (RTSPMessage * msg, RTSPStatusCode code,
|
||||||
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
g_hash_table_new_full (g_direct_hash, g_direct_equal, NULL, g_free);
|
||||||
|
|
||||||
if (request) {
|
if (request) {
|
||||||
/* FIXME copy headers */
|
gchar *header;
|
||||||
|
|
||||||
|
if (rtsp_message_get_header (request, RTSP_HDR_CSEQ, &header) == RTSP_OK) {
|
||||||
|
rtsp_message_add_header (msg, RTSP_HDR_CSEQ, header);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rtsp_message_get_header (request, RTSP_HDR_SESSION, &header) == RTSP_OK) {
|
||||||
|
char *pos;
|
||||||
|
|
||||||
|
header = g_strdup (header);
|
||||||
|
if ((pos = strchr (header, ';'))) {
|
||||||
|
*pos = '\0';
|
||||||
|
}
|
||||||
|
g_strchomp (header);
|
||||||
|
rtsp_message_add_header (msg, RTSP_HDR_SESSION, header);
|
||||||
|
g_free (header);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* FIXME copy more headers? */
|
||||||
}
|
}
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
|
@ -132,22 +182,28 @@ rtsp_message_unset (RTSPMessage * msg)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
msg->type = RTSP_MESSAGE_INVALID;
|
switch (msg->type) {
|
||||||
msg->type_data.request.method = RTSP_INVALID;
|
case RTSP_MESSAGE_INVALID:
|
||||||
|
break;
|
||||||
|
case RTSP_MESSAGE_REQUEST:
|
||||||
g_free (msg->type_data.request.uri);
|
g_free (msg->type_data.request.uri);
|
||||||
msg->type_data.request.uri = NULL;
|
break;
|
||||||
|
case RTSP_MESSAGE_RESPONSE:
|
||||||
msg->type_data.response.code = RTSP_STS_INVALID;
|
|
||||||
g_free (msg->type_data.response.reason);
|
g_free (msg->type_data.response.reason);
|
||||||
msg->type_data.response.reason = NULL;
|
break;
|
||||||
|
case RTSP_MESSAGE_DATA:
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
g_assert_not_reached ();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
if (msg->hdr_fields != NULL)
|
if (msg->hdr_fields != NULL)
|
||||||
g_hash_table_destroy (msg->hdr_fields);
|
g_hash_table_destroy (msg->hdr_fields);
|
||||||
msg->hdr_fields = NULL;
|
|
||||||
|
|
||||||
g_free (msg->body);
|
g_free (msg->body);
|
||||||
msg->body = NULL;
|
|
||||||
msg->body_size = 0;
|
memset (msg, 0, sizeof *msg);
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
}
|
}
|
||||||
|
@ -168,7 +224,7 @@ rtsp_message_free (RTSPMessage * msg)
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
|
rtsp_message_add_header (RTSPMessage * msg, RTSPHeaderField field,
|
||||||
gchar * value)
|
const gchar * value)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (value != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (value != NULL, RTSP_EINVAL);
|
||||||
|
@ -190,25 +246,25 @@ rtsp_message_remove_header (RTSPMessage * msg, RTSPHeaderField field)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_get_header (RTSPMessage * msg, RTSPHeaderField field,
|
rtsp_message_get_header (const RTSPMessage * msg, RTSPHeaderField field,
|
||||||
gchar ** value)
|
gchar ** value)
|
||||||
{
|
{
|
||||||
gchar *val;
|
gchar *val;
|
||||||
|
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (value != NULL, RTSP_EINVAL);
|
|
||||||
|
|
||||||
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
|
val = g_hash_table_lookup (msg->hdr_fields, GINT_TO_POINTER (field));
|
||||||
if (val == NULL)
|
if (val == NULL)
|
||||||
return RTSP_ENOTIMPL;
|
return RTSP_ENOTIMPL;
|
||||||
|
|
||||||
|
if (value)
|
||||||
*value = val;
|
*value = val;
|
||||||
|
|
||||||
return RTSP_OK;
|
return RTSP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_set_body (RTSPMessage * msg, guint8 * data, guint size)
|
rtsp_message_set_body (RTSPMessage * msg, const guint8 * data, guint size)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
|
|
||||||
|
@ -231,7 +287,7 @@ rtsp_message_take_body (RTSPMessage * msg, guint8 * data, guint size)
|
||||||
}
|
}
|
||||||
|
|
||||||
RTSPResult
|
RTSPResult
|
||||||
rtsp_message_get_body (RTSPMessage * msg, guint8 ** data, guint * size)
|
rtsp_message_get_body (const RTSPMessage * msg, guint8 ** data, guint * size)
|
||||||
{
|
{
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
|
||||||
|
@ -260,7 +316,7 @@ rtsp_message_steal_body (RTSPMessage * msg, guint8 ** data, guint * size)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
dump_mem (guint8 * mem, gint size)
|
dump_mem (guint8 * mem, guint size)
|
||||||
{
|
{
|
||||||
guint i, j;
|
guint i, j;
|
||||||
GString *string = g_string_sized_new (50);
|
GString *string = g_string_sized_new (50);
|
||||||
|
@ -309,7 +365,7 @@ rtsp_message_dump (RTSPMessage * msg)
|
||||||
|
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case RTSP_MESSAGE_REQUEST:
|
case RTSP_MESSAGE_REQUEST:
|
||||||
g_print ("request message %p\n", msg);
|
g_print ("RTSP request message %p\n", msg);
|
||||||
g_print (" request line:\n");
|
g_print (" request line:\n");
|
||||||
g_print (" method: '%s'\n",
|
g_print (" method: '%s'\n",
|
||||||
rtsp_method_as_text (msg->type_data.request.method));
|
rtsp_method_as_text (msg->type_data.request.method));
|
||||||
|
@ -321,7 +377,7 @@ rtsp_message_dump (RTSPMessage * msg)
|
||||||
dump_mem (data, size);
|
dump_mem (data, size);
|
||||||
break;
|
break;
|
||||||
case RTSP_MESSAGE_RESPONSE:
|
case RTSP_MESSAGE_RESPONSE:
|
||||||
g_print ("response message %p\n", msg);
|
g_print ("RTSP response message %p\n", msg);
|
||||||
g_print (" status line:\n");
|
g_print (" status line:\n");
|
||||||
g_print (" code: '%d'\n", msg->type_data.response.code);
|
g_print (" code: '%d'\n", msg->type_data.response.code);
|
||||||
g_print (" reason: '%s'\n", msg->type_data.response.reason);
|
g_print (" reason: '%s'\n", msg->type_data.response.reason);
|
||||||
|
@ -332,7 +388,7 @@ rtsp_message_dump (RTSPMessage * msg)
|
||||||
dump_mem (data, size);
|
dump_mem (data, size);
|
||||||
break;
|
break;
|
||||||
case RTSP_MESSAGE_DATA:
|
case RTSP_MESSAGE_DATA:
|
||||||
g_print ("data message %p\n", msg);
|
g_print ("RTSP data message %p\n", msg);
|
||||||
g_print (" channel: '%d'\n", msg->type_data.data.channel);
|
g_print (" channel: '%d'\n", msg->type_data.data.channel);
|
||||||
g_print (" size: '%d'\n", msg->body_size);
|
g_print (" size: '%d'\n", msg->body_size);
|
||||||
rtsp_message_get_body (msg, &data, &size);
|
rtsp_message_get_body (msg, &data, &size);
|
||||||
|
|
|
@ -82,27 +82,53 @@ typedef struct _RTSPMessage
|
||||||
|
|
||||||
} RTSPMessage;
|
} RTSPMessage;
|
||||||
|
|
||||||
RTSPResult rtsp_message_new_request (RTSPMessage **msg, RTSPMethod method, gchar *uri);
|
RTSPResult rtsp_message_new (RTSPMessage **msg);
|
||||||
RTSPResult rtsp_message_init_request (RTSPMessage *msg, RTSPMethod method, gchar *uri);
|
RTSPResult rtsp_message_init (RTSPMessage *msg);
|
||||||
|
|
||||||
RTSPResult rtsp_message_new_response (RTSPMessage **msg, RTSPStatusCode code, gchar *reason,
|
RTSPResult rtsp_message_new_request (RTSPMessage **msg,
|
||||||
RTSPMessage *request);
|
RTSPMethod method,
|
||||||
RTSPResult rtsp_message_init_response (RTSPMessage *msg, RTSPStatusCode code, gchar *reason,
|
const gchar *uri);
|
||||||
RTSPMessage *request);
|
RTSPResult rtsp_message_init_request (RTSPMessage *msg,
|
||||||
RTSPResult rtsp_message_init_data (RTSPMessage *msg, gint channel);
|
RTSPMethod method,
|
||||||
|
const gchar *uri);
|
||||||
|
|
||||||
|
RTSPResult rtsp_message_new_response (RTSPMessage **msg,
|
||||||
|
RTSPStatusCode code,
|
||||||
|
const gchar *reason,
|
||||||
|
const RTSPMessage *request);
|
||||||
|
RTSPResult rtsp_message_init_response (RTSPMessage *msg,
|
||||||
|
RTSPStatusCode code,
|
||||||
|
const gchar *reason,
|
||||||
|
const RTSPMessage *request);
|
||||||
|
|
||||||
|
RTSPResult rtsp_message_init_data (RTSPMessage *msg,
|
||||||
|
gint channel);
|
||||||
|
|
||||||
RTSPResult rtsp_message_unset (RTSPMessage *msg);
|
RTSPResult rtsp_message_unset (RTSPMessage *msg);
|
||||||
RTSPResult rtsp_message_free (RTSPMessage *msg);
|
RTSPResult rtsp_message_free (RTSPMessage *msg);
|
||||||
|
|
||||||
|
|
||||||
RTSPResult rtsp_message_add_header (RTSPMessage *msg, RTSPHeaderField field, gchar *value);
|
RTSPResult rtsp_message_add_header (RTSPMessage *msg,
|
||||||
RTSPResult rtsp_message_remove_header (RTSPMessage *msg, RTSPHeaderField field);
|
RTSPHeaderField field,
|
||||||
RTSPResult rtsp_message_get_header (RTSPMessage *msg, RTSPHeaderField field, gchar **value);
|
const gchar *value);
|
||||||
|
RTSPResult rtsp_message_remove_header (RTSPMessage *msg,
|
||||||
|
RTSPHeaderField field);
|
||||||
|
RTSPResult rtsp_message_get_header (const RTSPMessage *msg,
|
||||||
|
RTSPHeaderField field,
|
||||||
|
gchar **value);
|
||||||
|
|
||||||
RTSPResult rtsp_message_set_body (RTSPMessage *msg, guint8 *data, guint size);
|
RTSPResult rtsp_message_set_body (RTSPMessage *msg,
|
||||||
RTSPResult rtsp_message_take_body (RTSPMessage *msg, guint8 *data, guint size);
|
const guint8 *data,
|
||||||
RTSPResult rtsp_message_get_body (RTSPMessage *msg, guint8 **data, guint *size);
|
guint size);
|
||||||
RTSPResult rtsp_message_steal_body (RTSPMessage *msg, guint8 **data, guint *size);
|
RTSPResult rtsp_message_take_body (RTSPMessage *msg,
|
||||||
|
guint8 *data,
|
||||||
|
guint size);
|
||||||
|
RTSPResult rtsp_message_get_body (const RTSPMessage *msg,
|
||||||
|
guint8 **data,
|
||||||
|
guint *size);
|
||||||
|
RTSPResult rtsp_message_steal_body (RTSPMessage *msg,
|
||||||
|
guint8 **data,
|
||||||
|
guint *size);
|
||||||
|
|
||||||
RTSPResult rtsp_message_dump (RTSPMessage *msg);
|
RTSPResult rtsp_message_dump (RTSPMessage *msg);
|
||||||
|
|
||||||
|
|
|
@ -322,7 +322,7 @@ DEFINE_ARRAY_P_GETTER (attribute, attributes, SDPAttribute);
|
||||||
gchar *
|
gchar *
|
||||||
sdp_message_get_attribute_val_n (SDPMessage * msg, gchar * key, guint nth)
|
sdp_message_get_attribute_val_n (SDPMessage * msg, gchar * key, guint nth)
|
||||||
{
|
{
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
for (i = 0; i < msg->attributes->len; i++) {
|
for (i = 0; i < msg->attributes->len; i++) {
|
||||||
SDPAttribute *attr;
|
SDPAttribute *attr;
|
||||||
|
@ -423,7 +423,7 @@ sdp_media_get_attribute (SDPMedia * media, guint idx)
|
||||||
gchar *
|
gchar *
|
||||||
sdp_media_get_attribute_val_n (SDPMedia * media, gchar * key, guint nth)
|
sdp_media_get_attribute_val_n (SDPMedia * media, gchar * key, guint nth)
|
||||||
{
|
{
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
for (i = 0; i < media->attributes->len; i++) {
|
for (i = 0; i < media->attributes->len; i++) {
|
||||||
SDPAttribute *attr;
|
SDPAttribute *attr;
|
||||||
|
@ -454,9 +454,9 @@ sdp_media_get_format (SDPMedia * media, guint idx)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_string (gchar * dest, gint size, gchar ** src)
|
read_string (gchar * dest, guint size, gchar ** src)
|
||||||
{
|
{
|
||||||
gint idx;
|
guint idx;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
/* skip spaces */
|
/* skip spaces */
|
||||||
|
@ -473,9 +473,9 @@ read_string (gchar * dest, gint size, gchar ** src)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
read_string_del (gchar * dest, gint size, gchar del, gchar ** src)
|
read_string_del (gchar * dest, guint size, gchar del, gchar ** src)
|
||||||
{
|
{
|
||||||
gint idx;
|
guint idx;
|
||||||
|
|
||||||
idx = 0;
|
idx = 0;
|
||||||
/* skip spaces */
|
/* skip spaces */
|
||||||
|
@ -582,7 +582,7 @@ sdp_parse_line (SDPContext * c, gchar type, gchar * buffer)
|
||||||
case 'm':
|
case 'm':
|
||||||
{
|
{
|
||||||
gchar *slash;
|
gchar *slash;
|
||||||
SDPMedia nmedia = { 0 };
|
SDPMedia nmedia = {.media = NULL };
|
||||||
|
|
||||||
c->state = SDP_MEDIA;
|
c->state = SDP_MEDIA;
|
||||||
sdp_media_init (&nmedia);
|
sdp_media_init (&nmedia);
|
||||||
|
@ -622,7 +622,7 @@ sdp_message_parse_buffer (guint8 * data, guint size, SDPMessage * msg)
|
||||||
SDPContext c;
|
SDPContext c;
|
||||||
gchar type;
|
gchar type;
|
||||||
gchar buffer[MAX_LINE_LEN];
|
gchar buffer[MAX_LINE_LEN];
|
||||||
gint idx = 0;
|
guint idx = 0;
|
||||||
|
|
||||||
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (msg != NULL, RTSP_EINVAL);
|
||||||
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
|
g_return_val_if_fail (data != NULL, RTSP_EINVAL);
|
||||||
|
@ -672,7 +672,7 @@ print_media (SDPMedia * media)
|
||||||
g_print (" num_ports: '%d'\n", media->num_ports);
|
g_print (" num_ports: '%d'\n", media->num_ports);
|
||||||
g_print (" proto: '%s'\n", media->proto);
|
g_print (" proto: '%s'\n", media->proto);
|
||||||
if (media->fmts->len > 0) {
|
if (media->fmts->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" formats:\n");
|
g_print (" formats:\n");
|
||||||
for (i = 0; i < media->fmts->len; i++) {
|
for (i = 0; i < media->fmts->len; i++) {
|
||||||
|
@ -684,7 +684,7 @@ print_media (SDPMedia * media)
|
||||||
g_print (" type: '%s'\n", media->key.type);
|
g_print (" type: '%s'\n", media->key.type);
|
||||||
g_print (" data: '%s'\n", media->key.data);
|
g_print (" data: '%s'\n", media->key.data);
|
||||||
if (media->attributes->len > 0) {
|
if (media->attributes->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" attributes:\n");
|
g_print (" attributes:\n");
|
||||||
for (i = 0; i < media->attributes->len; i++) {
|
for (i = 0; i < media->attributes->len; i++) {
|
||||||
|
@ -714,7 +714,7 @@ sdp_message_dump (SDPMessage * msg)
|
||||||
g_print (" uri: '%s'\n", msg->uri);
|
g_print (" uri: '%s'\n", msg->uri);
|
||||||
|
|
||||||
if (msg->emails->len > 0) {
|
if (msg->emails->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" emails:\n");
|
g_print (" emails:\n");
|
||||||
for (i = 0; i < msg->emails->len; i++) {
|
for (i = 0; i < msg->emails->len; i++) {
|
||||||
|
@ -722,7 +722,7 @@ sdp_message_dump (SDPMessage * msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (msg->phones->len > 0) {
|
if (msg->phones->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" phones:\n");
|
g_print (" phones:\n");
|
||||||
for (i = 0; i < msg->phones->len; i++) {
|
for (i = 0; i < msg->phones->len; i++) {
|
||||||
|
@ -739,7 +739,7 @@ sdp_message_dump (SDPMessage * msg)
|
||||||
g_print (" type: '%s'\n", msg->key.type);
|
g_print (" type: '%s'\n", msg->key.type);
|
||||||
g_print (" data: '%s'\n", msg->key.data);
|
g_print (" data: '%s'\n", msg->key.data);
|
||||||
if (msg->attributes->len > 0) {
|
if (msg->attributes->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" attributes:\n");
|
g_print (" attributes:\n");
|
||||||
for (i = 0; i < msg->attributes->len; i++) {
|
for (i = 0; i < msg->attributes->len; i++) {
|
||||||
|
@ -749,7 +749,7 @@ sdp_message_dump (SDPMessage * msg)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (msg->medias->len > 0) {
|
if (msg->medias->len > 0) {
|
||||||
gint i;
|
guint i;
|
||||||
|
|
||||||
g_print (" medias:\n");
|
g_print (" medias:\n");
|
||||||
for (i = 0; i < msg->medias->len; i++) {
|
for (i = 0; i < msg->medias->len; i++) {
|
||||||
|
|
Loading…
Reference in a new issue