gst/rtsp/gstrtspsrc.*: Handle default clock-rates for static payload types, rearrange stuff so that the rtpmap field ...

Original commit message from CVS:
* gst/rtsp/gstrtspsrc.c: (find_stream_by_setup),
(gst_rtspsrc_create_stream), (gst_rtspsrc_stream_free),
(get_default_rate_for_pt), (gst_rtspsrc_parse_rtpmap),
(gst_rtspsrc_media_to_caps),
(gst_rtspsrc_stream_configure_transport),
(gst_rtspsrc_stream_configure_caps),
(gst_rtspsrc_activate_streams), (gst_rtspsrc_parse_rtpinfo):
* gst/rtsp/gstrtspsrc.h:
Handle default clock-rates for static payload types, rearrange stuff so
that the rtpmap field in the sdp can override the defaults.
Parse RTP-Info field to get the seqnum and timebase fields that should
go in the caps.
Delay configuring caps after we got the RTP-Info from the PLAY reply from
the server.
This commit is contained in:
Wim Taymans 2007-03-25 15:34:42 +00:00
parent c53ad3009d
commit 8f5fb88b5a
3 changed files with 206 additions and 31 deletions

View file

@ -1,3 +1,20 @@
2007-03-25 Wim Taymans <wim@fluendo.com>
* gst/rtsp/gstrtspsrc.c: (find_stream_by_setup),
(gst_rtspsrc_create_stream), (gst_rtspsrc_stream_free),
(get_default_rate_for_pt), (gst_rtspsrc_parse_rtpmap),
(gst_rtspsrc_media_to_caps),
(gst_rtspsrc_stream_configure_transport),
(gst_rtspsrc_stream_configure_caps),
(gst_rtspsrc_activate_streams), (gst_rtspsrc_parse_rtpinfo):
* gst/rtsp/gstrtspsrc.h:
Handle default clock-rates for static payload types, rearrange stuff so
that the rtpmap field in the sdp can override the defaults.
Parse RTP-Info field to get the seqnum and timebase fields that should
go in the caps.
Delay configuring caps after we got the RTP-Info from the PLAY reply from
the server.
2007-03-22 Wim Taymans <wim@fluendo.com>
Patch by: Christophe Dehais <christophe dot dehais at gmail dot com>

View file

@ -417,6 +417,23 @@ find_stream_by_udpsrc (GstRTSPStream * stream, gconstpointer a)
return -1;
}
static gint
find_stream_by_setup (GstRTSPStream * stream, gconstpointer a)
{
/* check qualified setup_url */
if (!strcmp (stream->setup_url, (gchar *) a))
return 0;
/* check original control_url */
if (!strcmp (stream->control_url, (gchar *) a))
return 0;
/* check if qualified setup_url ends with string */
if (g_str_has_suffix (stream->control_url, (gchar *) a))
return 0;
return -1;
}
static GstRTSPStream *
gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
{
@ -468,7 +485,10 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, SDPMessage * sdp, gint idx)
GST_DEBUG_OBJECT (src, " control: %s", GST_STR_NULL (control_url));
if (control_url != NULL) {
/* If the control_url starts with a '/' or a non rtsp: protocol we will most
stream->control_url = g_strdup (control_url);
/* Build a fully qualified url using the content_base if any or by prefixing
* the original request.
* If the control_url starts with a '/' or a non rtsp: protocol we will most
* likely build a URL that the server will fail to understand, this is ok,
* we will fail then. */
if (g_str_has_prefix (control_url, "rtsp://"))
@ -498,6 +518,7 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
if (stream->caps)
gst_caps_unref (stream->caps);
g_free (stream->control_url);
g_free (stream->setup_url);
for (i = 0; i < 2; i++) {
@ -556,6 +577,46 @@ gst_rtspsrc_cleanup (GstRTSPSrc * src)
src->props = NULL;
}
/* FIXME, this should go somewhere else, ideally
*/
static guint
get_default_rate_for_pt (gint pt)
{
switch (pt) {
case 0:
case 3:
case 4:
case 5:
case 7:
case 8:
case 9:
case 12:
case 13:
case 15:
case 18:
return 8000;
case 16:
return 11025;
case 17:
return 22050;
case 6:
return 16000;
case 10:
case 11:
return 44100;
case 14:
case 25:
case 26:
case 28:
case 31:
case 32:
case 33:
case 34:
return 90000;
default:
return -1;
}
}
#define PARSE_INT(p, del, res) \
G_STMT_START { \
@ -609,7 +670,7 @@ gst_rtspsrc_parse_rtpmap (gchar * rtpmap, gint * payload, gchar ** name,
PARSE_STRING (p, "/", *name);
if (*name == NULL) {
/* no rate, assume 0 then */
/* no rate, assume -1 then */
*name = p;
*rate = -1;
return TRUE;
@ -651,29 +712,41 @@ gst_rtspsrc_media_to_caps (gint pt, SDPMedia * media)
gchar *params = NULL;
gchar *tmp;
GstStructure *s;
gint payload = 0;
gboolean ret;
/* dynamic payloads need rtpmap */
if (pt >= 96) {
gint payload = 0;
gboolean ret;
if ((rtpmap = sdp_media_get_attribute_val (media, "rtpmap"))) {
ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, &params);
if (ret) {
if (payload != pt) {
/* FIXME, not fatal? */
g_warning ("rtpmap of wrong payload type");
name = NULL;
rate = -1;
params = NULL;
}
} else {
/* FIXME, not fatal? */
g_warning ("error parsing rtpmap");
/* get and parse rtpmap */
if ((rtpmap = sdp_media_get_attribute_val (media, "rtpmap"))) {
ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, &params);
if (ret) {
if (payload != pt) {
/* we ignore the rtpmap if the payload type is different. */
g_warning ("rtpmap of wrong payload type, ignoring");
name = NULL;
rate = -1;
params = NULL;
}
} else
} else {
/* if we failed to parse the rtpmap for a dynamic payload type, we have an
* error */
if (pt >= 96)
goto no_rtpmap;
/* else we can ignore */
g_warning ("error parsing rtpmap, ignoring");
}
} else {
/* dynamic payloads need rtpmap or we fail */
if (pt >= 96)
goto no_rtpmap;
}
/* check if we have a rate, if not, we need to look up the rate from the
* default rates based on the payload types. */
if (rate == -1) {
rate = get_default_rate_for_pt (pt);
/* we fail if we cannot find one */
if (rate == -1)
goto no_rate;
}
tmp = g_ascii_strdown (media->media, -1);
caps = gst_caps_new_simple ("application/x-unknown",
@ -745,6 +818,11 @@ no_rtpmap:
g_warning ("rtpmap type not given for dynamic payload %d", pt);
return NULL;
}
no_rate:
{
g_warning ("rate unknown for payload type %d", pt);
return NULL;
}
}
static gboolean
@ -1010,7 +1088,6 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
/* set caps and activate */
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);
outpad = gst_object_ref (stream->channelpad[0]);
@ -1067,9 +1144,6 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
GST_DEBUG_OBJECT (src, "setting up UDP source");
/* set caps */
g_object_set (G_OBJECT (stream->udpsrc[0]), "caps", stream->caps, NULL);
/* 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. */
@ -1120,7 +1194,6 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
GST_DEBUG_OBJECT (src, "creating ghostpad");
gst_pad_use_fixed_caps (outpad);
gst_pad_set_caps (outpad, stream->caps);
/* create ghostpad, don't add just yet, this will be done when we activate
* the stream. */
@ -1160,6 +1233,19 @@ start_session_failure:
}
}
static gboolean
gst_rtspsrc_stream_configure_caps (GstRTSPStream * stream)
{
/* configure the caps on the UDP source and the channelpad */
if (stream->udpsrc[0]) {
g_object_set (G_OBJECT (stream->udpsrc[0]), "caps", stream->caps, NULL);
}
if (stream->channelpad[0]) {
gst_pad_set_caps (stream->channelpad[0], stream->caps);
}
return TRUE;
}
/* Adds the source pads of all configured streams to the element.
* This code is performed when we detected dataflow.
*
@ -1171,6 +1257,8 @@ gst_rtspsrc_activate_streams (GstRTSPSrc * src)
{
GList *walk;
GST_DEBUG_OBJECT (src, "activating streams");
for (walk = src->streams; walk; walk = g_list_next (walk)) {
GstRTSPStream *stream = (GstRTSPStream *) walk->data;
@ -1183,6 +1271,7 @@ gst_rtspsrc_activate_streams (GstRTSPSrc * src)
gst_pad_set_active (stream->srcpad, TRUE);
/* add the pad */
if (!stream->added) {
gst_pad_set_caps (stream->srcpad, stream->caps);
gst_element_add_pad (GST_ELEMENT_CAST (src), stream->srcpad);
stream->added = TRUE;
}
@ -2063,6 +2152,18 @@ failed:
}
}
/* Perform the SETUP request for all the streams.
*
* We ask the server for a specific transport, which initially includes all the
* ones we can support (UDP/TCP/MULTICAST). For the UDP transport we allocate
* two local UDP ports that we send to the server.
*
* Once the server replied with a transport, we configure the other streams
* with the same transport.
*
* This function will also configure the stream for the selected transport,
* which basically means creating the pipeline.
*/
static gboolean
gst_rtspsrc_setup_streams (GstRTSPSrc * src)
{
@ -2497,16 +2598,69 @@ static gboolean
gst_rtspsrc_parse_rtpinfo (GstRTSPSrc * src, gchar * rtpinfo)
{
gchar **infos;
gint i;
gint i, j;
GST_DEBUG_OBJECT (src, "parsing RTP-Info %s", rtpinfo);
infos = g_strsplit (rtpinfo, ",", 0);
for (i = 0; infos[i]; i++) {
/* FIXME, do something here:
* parse url, find stream for url.
gchar **fields;
GstRTSPStream *stream;
gint32 seqbase;
gint64 timebase;
GST_DEBUG_OBJECT (src, "parsing info %s", infos[i]);
/* init values, types of seqbase and timebase are bigger than needed so we can
* store -1 as uninitialized values */
stream = NULL;
seqbase = -1;
timebase = -1;
/* parse url, find stream for url.
* parse seq and rtptime. The seq number should be configured in the rtp
* depayloader or session manager to detect gaps. Same for the rtptime, it
* should be used to create an initial time newsegment.
*/
* should be used to create an initial time newsegment. */
fields = g_strsplit (infos[i], ";", 0);
for (j = 0; fields[j]; j++) {
GST_DEBUG_OBJECT (src, "parsing field %s", fields[j]);
/* remove leading whitespace */
fields[j] = g_strchug (fields[j]);
if (g_str_has_prefix (fields[j], "url=")) {
GList *lstream;
/* get the url and the stream */
lstream = g_list_find_custom (src->streams, (fields[j] + 4),
(GCompareFunc) find_stream_by_setup);
if (lstream)
stream = (GstRTSPStream *) lstream->data;
} else if (g_str_has_prefix (fields[j], "seq=")) {
seqbase = atoi (fields[j] + 4);
} else if (g_str_has_prefix (fields[j], "rtptime=")) {
timebase = atol (fields[j] + 8);
}
}
/* now we need to store the values in the caps of the stream and make sure
* that the UDP elements have the same caps property set before they receive
* the first buffer. */
if (stream != NULL) {
GstCaps *caps;
GST_DEBUG_OBJECT (src,
"found stream %p, seqbase %d, timebase %" G_GINT64_FORMAT, stream,
seqbase, timebase);
/* we have a stream, configure detected params */
stream->seqbase = seqbase;
stream->timebase = timebase;
if ((caps = stream->caps)) {
/* update caps */
gst_caps_set_simple (caps, "clock-base", G_TYPE_UINT, timebase,
"seqnum-base", G_TYPE_UINT, seqbase, NULL);
/* and configure the stream caps */
gst_rtspsrc_stream_configure_caps (stream);
}
}
}
g_strfreev (infos);

View file

@ -103,9 +103,13 @@ struct _GstRTSPStream {
/* state */
gint pt;
gboolean container;
/* original control url */
gchar *control_url;
/* fully qualified control url */
gchar *setup_url;
guint32 ssrc;
guint32 seqbase;
guint64 timebase;
};
struct _GstRTSPSrc {