mirror of
https://gitlab.freedesktop.org/gstreamer/gstreamer.git
synced 2025-02-17 11:45:25 +00:00
rtspsrc: Add support for multiple payload types
A media stream can have multiple payload types. Parse all the payload types and collect the caps information. We then have to store the pt<->caps mapping instead of 1 pt and 1 caps. Parse the profile from the SDP and use that to negotiate the transport instead of always using AVP. Rework how we do some tweaks for ASF and Realmedia.
This commit is contained in:
parent
dbe92c9147
commit
70de0e4e99
2 changed files with 207 additions and 108 deletions
|
@ -296,6 +296,12 @@ static gboolean gst_rtspsrc_stream_push_event (GstRTSPSrc * src,
|
|||
GstRTSPStream * stream, GstEvent * event);
|
||||
static gboolean gst_rtspsrc_push_event (GstRTSPSrc * src, GstEvent * event);
|
||||
|
||||
typedef struct
|
||||
{
|
||||
guint8 pt;
|
||||
GstCaps *caps;
|
||||
} PtMapItem;
|
||||
|
||||
/* commands we send to out loop to notify it of events */
|
||||
#define CMD_OPEN (1 << 0)
|
||||
#define CMD_PLAY (1 << 1)
|
||||
|
@ -1147,15 +1153,6 @@ find_stream_by_channel (GstRTSPStream * stream, gint * channel)
|
|||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
find_stream_by_pt (GstRTSPStream * stream, gint * pt)
|
||||
{
|
||||
if (stream->pt == *pt)
|
||||
return 0;
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
static gint
|
||||
find_stream_by_udpsrc (GstRTSPStream * stream, gconstpointer a)
|
||||
{
|
||||
|
@ -1299,28 +1296,72 @@ gst_rtspsrc_collect_connections (GstRTSPSrc * src, const GstSDPMessage * sdp,
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
/* m=<media> <UDP port> RTP/AVP <payload>
|
||||
*/
|
||||
static void
|
||||
gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
|
||||
const GstSDPMedia * media, GstRTSPStream * stream)
|
||||
{
|
||||
const gchar *payload;
|
||||
guint i, len;
|
||||
const gchar *proto;
|
||||
|
||||
/* get proto */
|
||||
proto = gst_sdp_media_get_proto (media);
|
||||
if (proto == NULL)
|
||||
goto no_proto;
|
||||
|
||||
if (g_str_equal (proto, "RTP/AVP"))
|
||||
stream->profile = GST_RTSP_PROFILE_AVP;
|
||||
else if (g_str_equal (proto, "RTP/SAVP"))
|
||||
stream->profile = GST_RTSP_PROFILE_SAVP;
|
||||
else if (g_str_equal (proto, "RTP/AVPF"))
|
||||
stream->profile = GST_RTSP_PROFILE_AVPF;
|
||||
else if (g_str_equal (proto, "RTP/SAVPF"))
|
||||
stream->profile = GST_RTSP_PROFILE_SAVPF;
|
||||
else
|
||||
goto unknown_proto;
|
||||
|
||||
len = gst_sdp_media_formats_len (media);
|
||||
for (i = 0; i < len; i++) {
|
||||
gint pt;
|
||||
GstCaps *caps;
|
||||
GstStructure *s;
|
||||
const gchar *enc;
|
||||
PtMapItem item;
|
||||
|
||||
pt = atoi (gst_sdp_media_get_format (media, i));
|
||||
|
||||
GST_DEBUG_OBJECT (src, " looking at %d pt: %d", i, pt);
|
||||
|
||||
/* we must have a payload. No payload means we cannot create caps */
|
||||
/* FIXME, handle multiple formats. The problem here is that we just want to
|
||||
* take the first available format that we can handle but in order to do that
|
||||
* we need to scan for depayloader plugins. Scanning for payloader plugins is
|
||||
* also suboptimal because the user maybe just wants to save the raw stream
|
||||
* and then we don't care. */
|
||||
if ((payload = gst_sdp_media_get_format (media, 0))) {
|
||||
stream->pt = atoi (payload);
|
||||
/* convert caps */
|
||||
stream->caps = gst_rtspsrc_media_to_caps (stream->pt, media);
|
||||
caps = gst_rtspsrc_media_to_caps (pt, media);
|
||||
if (caps == NULL) {
|
||||
GST_WARNING_OBJECT (src, " skipping pt %d without caps", pt);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* do some tweaks */
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
if ((enc = gst_structure_get_string (s, "encoding-name"))) {
|
||||
stream->is_real = (strstr (enc, "-REAL") != NULL);
|
||||
if (strcmp (enc, "X-ASF-PF") == 0)
|
||||
stream->container = TRUE;
|
||||
}
|
||||
GST_DEBUG ("mapping sdp session level attributes to caps");
|
||||
gst_rtspsrc_sdp_attributes_to_caps (sdp->attributes, stream->caps);
|
||||
gst_rtspsrc_sdp_attributes_to_caps (sdp->attributes, caps);
|
||||
GST_DEBUG ("mapping sdp media level attributes to caps");
|
||||
gst_rtspsrc_sdp_attributes_to_caps (media->attributes, stream->caps);
|
||||
gst_rtspsrc_sdp_attributes_to_caps (media->attributes, caps);
|
||||
|
||||
/* the first pt will be the default */
|
||||
if (stream->ptmap->len == 0)
|
||||
stream->default_pt = pt;
|
||||
|
||||
item.pt = pt;
|
||||
item.caps = caps;
|
||||
g_array_append_val (stream->ptmap, item);
|
||||
|
||||
#if 0
|
||||
if (stream->pt >= 96) {
|
||||
/* If we have a dynamic payload type, see if we have a stream with the
|
||||
* same payload number. If there is one, they are part of the same
|
||||
|
@ -1331,6 +1372,19 @@ gst_rtspsrc_collect_payloads (GstRTSPSrc * src, const GstSDPMessage * sdp,
|
|||
stream->pt);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return;
|
||||
|
||||
no_proto:
|
||||
{
|
||||
GST_ERROR_OBJECT (src, "can't find proto in media");
|
||||
return;
|
||||
}
|
||||
unknown_proto:
|
||||
{
|
||||
GST_ERROR_OBJECT (src, "unknown proto in media %s", proto);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1375,6 +1429,8 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, GstSDPMessage * sdp, gint idx)
|
|||
stream->discont = TRUE;
|
||||
stream->seqbase = -1;
|
||||
stream->timebase = -1;
|
||||
stream->profile = GST_RTSP_PROFILE_AVP;
|
||||
stream->ptmap = g_array_new (FALSE, FALSE, sizeof (PtMapItem));
|
||||
|
||||
/* collect bandwidth information for this steam. FIXME, configure in the RTP
|
||||
* session manager to scale RTCP. */
|
||||
|
@ -1383,6 +1439,7 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, GstSDPMessage * sdp, gint idx)
|
|||
/* collect connection info */
|
||||
gst_rtspsrc_collect_connections (src, sdp, media, stream);
|
||||
|
||||
/* make the payload type map */
|
||||
gst_rtspsrc_collect_payloads (src, sdp, media, stream);
|
||||
|
||||
/* collect port number */
|
||||
|
@ -1396,10 +1453,8 @@ gst_rtspsrc_create_stream (GstRTSPSrc * src, GstSDPMessage * sdp, gint idx)
|
|||
control_url = gst_sdp_message_get_attribute_val_n (sdp, "control", 0);
|
||||
|
||||
GST_DEBUG_OBJECT (src, "stream %d, (%p)", stream->id, stream);
|
||||
GST_DEBUG_OBJECT (src, " pt: %d", stream->pt);
|
||||
GST_DEBUG_OBJECT (src, " port: %d", stream->port);
|
||||
GST_DEBUG_OBJECT (src, " container: %d", stream->container);
|
||||
GST_DEBUG_OBJECT (src, " caps: %" GST_PTR_FORMAT, stream->caps);
|
||||
GST_DEBUG_OBJECT (src, " control: %s", GST_STR_NULL (control_url));
|
||||
|
||||
if (control_url != NULL) {
|
||||
|
@ -1447,8 +1502,7 @@ gst_rtspsrc_stream_free (GstRTSPSrc * src, GstRTSPStream * stream)
|
|||
|
||||
GST_DEBUG_OBJECT (src, "free stream %p", stream);
|
||||
|
||||
if (stream->caps)
|
||||
gst_caps_unref (stream->caps);
|
||||
g_array_free (stream->ptmap, TRUE);
|
||||
|
||||
g_free (stream->destination);
|
||||
g_free (stream->control_url);
|
||||
|
@ -1678,10 +1732,31 @@ gst_rtspsrc_sdp_attributes_to_caps (GArray * attributes, GstCaps * caps)
|
|||
}
|
||||
}
|
||||
|
||||
static const gchar *
|
||||
rtsp_get_attribute_for_pt (const GstSDPMedia * media, const gchar * name,
|
||||
gint pt)
|
||||
{
|
||||
guint i;
|
||||
|
||||
for (i = 0;; i++) {
|
||||
const gchar *attr;
|
||||
gint val;
|
||||
|
||||
if ((attr = gst_sdp_media_get_attribute_val_n (media, name, i)) == NULL)
|
||||
break;
|
||||
|
||||
if (sscanf (attr, "%d ", &val) != 1)
|
||||
continue;
|
||||
|
||||
if (val == pt)
|
||||
return attr;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mapping of caps to and from SDP fields:
|
||||
*
|
||||
* m=<media> <UDP port> RTP/AVP <payload>
|
||||
* a=rtpmap:<payload> <encoding_name>/<clock_rate>[/<encoding_params>]
|
||||
* a=fmtp:<payload> <param>[=<value>];...
|
||||
*/
|
||||
|
@ -1700,29 +1775,17 @@ gst_rtspsrc_media_to_caps (gint pt, const GstSDPMedia * media)
|
|||
gboolean ret;
|
||||
|
||||
/* get and parse rtpmap */
|
||||
if ((rtpmap = gst_sdp_media_get_attribute_val (media, "rtpmap"))) {
|
||||
ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
|
||||
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 {
|
||||
/* 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;
|
||||
rtpmap = rtsp_get_attribute_for_pt (media, "rtpmap", pt);
|
||||
|
||||
/* dynamic payloads need rtpmap or we fail */
|
||||
if (rtpmap == NULL && pt >= 96)
|
||||
goto no_rtpmap;
|
||||
|
||||
ret = gst_rtspsrc_parse_rtpmap (rtpmap, &payload, &name, &rate, ¶ms);
|
||||
if (!ret) {
|
||||
g_warning ("error parsing rtpmap, ignoring");
|
||||
}
|
||||
|
||||
/* 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) {
|
||||
|
@ -1770,7 +1833,7 @@ gst_rtspsrc_media_to_caps (gint pt, const GstSDPMedia * media)
|
|||
}
|
||||
|
||||
/* parse optional fmtp: field */
|
||||
if ((fmtp = gst_sdp_media_get_attribute_val (media, "fmtp"))) {
|
||||
if ((fmtp = rtsp_get_attribute_for_pt (media, "fmtp", pt))) {
|
||||
gchar *p;
|
||||
gint payload = 0;
|
||||
|
||||
|
@ -2599,6 +2662,20 @@ unknown_stream:
|
|||
}
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
stream_get_caps_for_pt (GstRTSPStream * stream, guint pt)
|
||||
{
|
||||
guint i, len;
|
||||
|
||||
len = stream->ptmap->len;
|
||||
for (i = 0; i < len; i++) {
|
||||
PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
|
||||
if (item->pt == pt)
|
||||
return item->caps;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static GstCaps *
|
||||
request_pt_map (GstElement * manager, guint session, guint pt, GstRTSPSrc * src)
|
||||
{
|
||||
|
@ -2612,8 +2689,7 @@ request_pt_map (GstElement * manager, guint session, guint pt, GstRTSPSrc * src)
|
|||
if (!stream)
|
||||
goto unknown_stream;
|
||||
|
||||
caps = stream->caps;
|
||||
if (caps)
|
||||
if ((caps = stream_get_caps_for_pt (stream, pt)))
|
||||
gst_caps_ref (caps);
|
||||
GST_RTSP_STATE_UNLOCK (src);
|
||||
|
||||
|
@ -2767,9 +2843,6 @@ gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
|
|||
/* configure the manager */
|
||||
if (src->manager == NULL) {
|
||||
GObjectClass *klass;
|
||||
GstStructure *s;
|
||||
const gchar *encoding;
|
||||
gboolean need_slave;
|
||||
|
||||
if (!(src->manager = gst_element_factory_make (manager, "manager"))) {
|
||||
/* fallback */
|
||||
|
@ -2818,15 +2891,11 @@ gst_rtspsrc_stream_configure_manager (GstRTSPSrc * src, GstRTSPStream * stream,
|
|||
* with such input times, e.g. container ones, most notably ASF */
|
||||
/* TODO alternatives are having an event that indicates these shifts,
|
||||
* or having rtsp extensions provide suggestion on buffer mode */
|
||||
need_slave = stream->container;
|
||||
if (stream->caps && (s = gst_caps_get_structure (stream->caps, 0)) &&
|
||||
(encoding = gst_structure_get_string (s, "encoding-name")))
|
||||
need_slave = need_slave || (strcmp (encoding, "X-ASF-PF") == 0);
|
||||
/* valid duration implies not likely live pipeline,
|
||||
* so slaving in jitterbuffer does not make much sense
|
||||
* (and might mess things up due to bursts) */
|
||||
if (GST_CLOCK_TIME_IS_VALID (src->segment.duration) &&
|
||||
src->segment.duration && !need_slave) {
|
||||
src->segment.duration && !stream->container) {
|
||||
src->use_buffering = TRUE;
|
||||
} else {
|
||||
src->use_buffering = FALSE;
|
||||
|
@ -3423,15 +3492,13 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
|||
GstPad *outpad = NULL;
|
||||
GstPadTemplate *template;
|
||||
gchar *name;
|
||||
GstStructure *s;
|
||||
const gchar *media_type;
|
||||
guint i, len;
|
||||
|
||||
src = stream->parent;
|
||||
|
||||
GST_DEBUG_OBJECT (src, "configuring transport for stream %p", stream);
|
||||
|
||||
s = gst_caps_get_structure (stream->caps, 0);
|
||||
|
||||
/* get the proper media type for this stream now */
|
||||
if (gst_rtsp_transport_get_media_type (transport, &media_type) < 0)
|
||||
goto unknown_transport;
|
||||
|
@ -3440,7 +3507,18 @@ gst_rtspsrc_stream_configure_transport (GstRTSPStream * stream,
|
|||
|
||||
/* configure the final media type */
|
||||
GST_DEBUG_OBJECT (src, "setting media type to %s", media_type);
|
||||
gst_structure_set_name (s, media_type);
|
||||
|
||||
len = stream->ptmap->len;
|
||||
for (i = 0; i < len; i++) {
|
||||
GstStructure *s;
|
||||
PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
|
||||
|
||||
if (item->caps == NULL)
|
||||
continue;
|
||||
|
||||
s = gst_caps_get_structure (item->caps, 0);
|
||||
gst_structure_set_name (s, media_type);
|
||||
}
|
||||
|
||||
/* try to get and configure a manager, channelpad[0-1] will be configured with
|
||||
* the pads for the manager, or NULL when no manager is needed. */
|
||||
|
@ -3561,8 +3639,11 @@ gst_rtspsrc_activate_streams (GstRTSPSrc * src)
|
|||
/* if we don't have a session manager, set the caps now. If we have a
|
||||
* session, we will get a notification of the pad and the caps. */
|
||||
if (!src->manager) {
|
||||
GstCaps *caps;
|
||||
|
||||
caps = stream_get_caps_for_pt (stream, stream->default_pt);
|
||||
GST_DEBUG_OBJECT (src, "setting pad caps for stream %p", stream);
|
||||
gst_pad_set_caps (stream->srcpad, stream->caps);
|
||||
gst_pad_set_caps (stream->srcpad, caps);
|
||||
}
|
||||
/* add the pad */
|
||||
if (!stream->added) {
|
||||
|
@ -3604,10 +3685,17 @@ gst_rtspsrc_configure_caps (GstRTSPSrc * src, GstSegment * segment,
|
|||
|
||||
for (walk = src->streams; walk; walk = g_list_next (walk)) {
|
||||
GstRTSPStream *stream = (GstRTSPStream *) walk->data;
|
||||
GstCaps *caps;
|
||||
guint j, len;
|
||||
|
||||
if ((caps = stream->caps)) {
|
||||
caps = gst_caps_make_writable (caps);
|
||||
len = stream->ptmap->len;
|
||||
for (j = 0; j < len; j++) {
|
||||
GstCaps *caps;
|
||||
PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, j);
|
||||
|
||||
if (item->caps == NULL)
|
||||
continue;
|
||||
|
||||
caps = gst_caps_make_writable (item->caps);
|
||||
/* update caps */
|
||||
if (stream->timebase != -1)
|
||||
gst_caps_set_simple (caps, "clock-base", G_TYPE_UINT,
|
||||
|
@ -3621,9 +3709,10 @@ gst_rtspsrc_configure_caps (GstRTSPSrc * src, GstSegment * segment,
|
|||
gst_caps_set_simple (caps, "play-speed", G_TYPE_DOUBLE, play_speed, NULL);
|
||||
gst_caps_set_simple (caps, "play-scale", G_TYPE_DOUBLE, play_scale, NULL);
|
||||
|
||||
stream->caps = caps;
|
||||
item->caps = caps;
|
||||
GST_DEBUG_OBJECT (src, "stream %p, pt %d, caps %" GST_PTR_FORMAT, stream,
|
||||
item->pt, caps);
|
||||
}
|
||||
GST_DEBUG_OBJECT (src, "stream %p, caps %" GST_PTR_FORMAT, stream, caps);
|
||||
}
|
||||
if (reset_manager && src->manager) {
|
||||
GST_DEBUG_OBJECT (src, "clear session");
|
||||
|
@ -5330,7 +5419,7 @@ static guint protocol_masks[] = {
|
|||
|
||||
static GstRTSPResult
|
||||
gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
|
||||
GstRTSPLowerTrans protocols, gchar ** transports)
|
||||
GstRTSPLowerTrans protocols, GstRTSPProfile profile, gchar ** transports)
|
||||
{
|
||||
GstRTSPResult res;
|
||||
GString *result;
|
||||
|
@ -5354,23 +5443,35 @@ gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
|
|||
add_udp_str = FALSE;
|
||||
|
||||
/* the default RTSP transports */
|
||||
result = g_string_new ("");
|
||||
result = g_string_new ("RTP");
|
||||
|
||||
switch (profile) {
|
||||
case GST_RTSP_PROFILE_AVP:
|
||||
g_string_append (result, "/AVP");
|
||||
break;
|
||||
case GST_RTSP_PROFILE_SAVP:
|
||||
g_string_append (result, "/SAVP");
|
||||
break;
|
||||
case GST_RTSP_PROFILE_AVPF:
|
||||
g_string_append (result, "/AVPF");
|
||||
break;
|
||||
case GST_RTSP_PROFILE_SAVPF:
|
||||
g_string_append (result, "/SAVPF");
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
if (protocols & GST_RTSP_LOWER_TRANS_UDP) {
|
||||
GST_DEBUG_OBJECT (src, "adding UDP unicast");
|
||||
|
||||
g_string_append (result, "RTP/AVP");
|
||||
if (add_udp_str)
|
||||
g_string_append (result, "/UDP");
|
||||
g_string_append (result, ";unicast;client_port=%%u1-%%u2");
|
||||
} else if (protocols & GST_RTSP_LOWER_TRANS_UDP_MCAST) {
|
||||
GST_DEBUG_OBJECT (src, "adding UDP multicast");
|
||||
|
||||
/* we don't have to allocate any UDP ports yet, if the selected transport
|
||||
* turns out to be multicast we can create them and join the multicast
|
||||
* group indicated in the transport reply */
|
||||
if (result->len > 0)
|
||||
g_string_append (result, ",");
|
||||
g_string_append (result, "RTP/AVP");
|
||||
if (add_udp_str)
|
||||
g_string_append (result, "/UDP");
|
||||
g_string_append (result, ";multicast");
|
||||
|
@ -5385,9 +5486,7 @@ gst_rtspsrc_create_transports_string (GstRTSPSrc * src,
|
|||
} else if (protocols & GST_RTSP_LOWER_TRANS_TCP) {
|
||||
GST_DEBUG_OBJECT (src, "adding TCP");
|
||||
|
||||
if (result->len > 0)
|
||||
g_string_append (result, ",");
|
||||
g_string_append (result, "RTP/AVP/TCP;unicast;interleaved=%%i1-%%i2");
|
||||
g_string_append (result, "/TCP;unicast;interleaved=%%i1-%%i2");
|
||||
}
|
||||
*transports = g_string_free (result, FALSE);
|
||||
|
||||
|
@ -5484,23 +5583,6 @@ failed:
|
|||
}
|
||||
}
|
||||
|
||||
static gboolean
|
||||
gst_rtspsrc_stream_is_real_media (GstRTSPStream * stream)
|
||||
{
|
||||
gboolean res = FALSE;
|
||||
|
||||
if (stream->caps) {
|
||||
GstStructure *s;
|
||||
const gchar *enc = NULL;
|
||||
|
||||
s = gst_caps_get_structure (stream->caps, 0);
|
||||
if ((enc = gst_structure_get_string (s, "encoding-name"))) {
|
||||
res = (strstr (enc, "-REAL") != NULL);
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/* Perform the SETUP request for all the streams.
|
||||
*
|
||||
* We ask the server for a specific transport, which initially includes all the
|
||||
|
@ -5558,11 +5640,17 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
|
|||
gint retry = 0;
|
||||
guint mask = 0;
|
||||
gboolean selected;
|
||||
GstCaps *caps;
|
||||
|
||||
stream = (GstRTSPStream *) walk->data;
|
||||
caps = stream_get_caps_for_pt (stream, stream->default_pt);
|
||||
if (caps == NULL) {
|
||||
GST_DEBUG_OBJECT (src, "skipping stream %p, no caps", stream);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* see if we need to configure this stream */
|
||||
if (!gst_rtsp_ext_list_configure_stream (src->extensions, stream->caps)) {
|
||||
if (!gst_rtsp_ext_list_configure_stream (src->extensions, caps)) {
|
||||
GST_DEBUG_OBJECT (src, "skipping stream %p, disabled by extension",
|
||||
stream);
|
||||
stream->disabled = TRUE;
|
||||
|
@ -5570,7 +5658,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
|
|||
}
|
||||
|
||||
g_signal_emit (src, gst_rtspsrc_signals[SIGNAL_SELECT_STREAM], 0,
|
||||
stream->id, stream->caps, &selected);
|
||||
stream->id, caps, &selected);
|
||||
if (!selected) {
|
||||
GST_DEBUG_OBJECT (src, "skipping stream %p, disabled by signal", stream);
|
||||
stream->disabled = TRUE;
|
||||
|
@ -5579,11 +5667,11 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
|
|||
stream->disabled = FALSE;
|
||||
|
||||
/* merge/overwrite global caps */
|
||||
if (stream->caps) {
|
||||
if (caps) {
|
||||
guint j, num;
|
||||
GstStructure *s;
|
||||
|
||||
s = gst_caps_get_structure (stream->caps, 0);
|
||||
s = gst_caps_get_structure (caps, 0);
|
||||
|
||||
num = gst_structure_n_fields (src->props);
|
||||
for (j = 0; j < num; j++) {
|
||||
|
@ -5633,7 +5721,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
|
|||
/* create a string with first transport in line */
|
||||
transports = NULL;
|
||||
res = gst_rtspsrc_create_transports_string (src,
|
||||
protocols & protocol_masks[mask], &transports);
|
||||
protocols & protocol_masks[mask], stream->profile, &transports);
|
||||
if (res < 0 || transports == NULL)
|
||||
goto setup_transport_failed;
|
||||
|
||||
|
@ -5705,7 +5793,7 @@ gst_rtspsrc_setup_streams (GstRTSPSrc * src, gboolean async)
|
|||
* but not without checking for lost cause/extension so we can
|
||||
* post a nicer/more useful error message later */
|
||||
if (!unsupported_real)
|
||||
unsupported_real = gst_rtspsrc_stream_is_real_media (stream);
|
||||
unsupported_real = stream->is_real;
|
||||
/* select next available protocol, give up on this stream if none */
|
||||
mask++;
|
||||
while (protocol_masks[mask] && !(protocols & protocol_masks[mask]))
|
||||
|
@ -6619,13 +6707,21 @@ gen_range_header (GstRTSPSrc * src, GstSegment * segment)
|
|||
static void
|
||||
clear_rtp_base (GstRTSPSrc * src, GstRTSPStream * stream)
|
||||
{
|
||||
guint i, len;
|
||||
|
||||
stream->timebase = -1;
|
||||
stream->seqbase = -1;
|
||||
if (stream->caps) {
|
||||
|
||||
len = stream->ptmap->len;
|
||||
for (i = 0; i < len; i++) {
|
||||
PtMapItem *item = &g_array_index (stream->ptmap, PtMapItem, i);
|
||||
GstStructure *s;
|
||||
|
||||
stream->caps = gst_caps_make_writable (stream->caps);
|
||||
s = gst_caps_get_structure (stream->caps, 0);
|
||||
if (item->caps == NULL)
|
||||
continue;
|
||||
|
||||
item->caps = gst_caps_make_writable (item->caps);
|
||||
s = gst_caps_get_structure (item->caps, 0);
|
||||
gst_structure_remove_fields (s, "clock-base", "seqnum-base", NULL);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -108,7 +108,6 @@ struct _GstRTSPStream {
|
|||
|
||||
/* for interleaved mode */
|
||||
guint8 channel[2];
|
||||
GstCaps *caps;
|
||||
GstPad *channelpad[2];
|
||||
|
||||
/* our udp sources */
|
||||
|
@ -125,9 +124,12 @@ struct _GstRTSPStream {
|
|||
GstElement *fakesrc;
|
||||
|
||||
/* state */
|
||||
gint pt;
|
||||
guint port;
|
||||
gboolean container;
|
||||
gboolean is_real;
|
||||
guint8 default_pt;
|
||||
GstRTSPProfile profile;
|
||||
GArray *ptmap;
|
||||
/* original control url */
|
||||
gchar *control_url;
|
||||
guint32 ssrc;
|
||||
|
@ -149,6 +151,7 @@ struct _GstRTSPStream {
|
|||
gchar *destination;
|
||||
gboolean is_multicast;
|
||||
guint ttl;
|
||||
|
||||
};
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in a new issue